| generate_threat_modelA | Generate a complete threat model from a feature description. Analyzes the feature using the Security Properties (Confidentiality,
Integrity, Availability, Usage) methodology with capability-defined
attackers. Produces trust boundaries, asset inventory, attacker
inventory, control objective matrix, and assumptions. Runs a multi-step AI pipeline. Progress is reported automatically. Similar-model short-circuit: if the backend finds an existing
model in the workspace whose feature description substantially
overlaps with the new one, it does NOT generate a duplicate. This
tool returns {"similar_models": [{"id", "title", "reason"}, ...], "suggestion": "..."} with the candidate IDs instead. The agent
should then either: Call refine_threat_model on one of the candidates to extend
the existing model (usually the right answer — avoids duplicate
modeling of the same system and preserves control/assertion
history). Retry this tool with force=True to bypass the check and
create a genuinely new model anyway (e.g., when the similarity
is superficial and the operator confirmed the new model is
distinct).
|
| refine_threat_modelA | Refine an existing threat model based on an instruction. Updates the model's assets, attackers, trust boundaries, and
control objectives based on the instruction. Creates a new
version. Progress is reported automatically. Refine CANNOT silently replace an entity's identity under a
stable ID or silently drop an entity. Behavior: Preserved entities where the LLM proposed an identity-
bearing rewrite (name / description / security_properties on
assets; capability / archetype / position on attackers) run
through a semantic-preservation guard. Rewrites classified as
replace or ambiguous (or unavailable if the gate
LLM is down) have their identity fields REVERTED to the
pre-refine values. Each rejection shows up as an entry in the
semantic_rejections array in this tool's return value —
surface these to the operator. Entities the LLM drops from the refined output are re-
appended to the model unchanged. The only sanctioned removal
path is remove_entity (entity_type="asset") / remove_entity (entity_type="attacker") (soft-delete). CO IDs are stable across refinements; pairs (asset,
attacker) that disappear come back as tombstones with
removed=True (not renumbered). Controls that only mapped
to tombstoned COs become orphaned at read time.
|
| query_threat_modelA | Ask a natural-language question about an existing threat model. Read-only; no side effects (no new version, no mutation). Uses AI to answer questions grounded in the model's assets, attackers, control objectives, assumptions, and current security posture, returning {model_id, answer} where answer is prose. Use this for interpretation or summary questions ("what are the biggest gaps?", "which attackers target the token store?"). Do NOT use it to change the model — use refine_threat_model for that — and prefer get_threat_model / assess_model when you need structured data (entity lists, coverage counts) rather than a written answer. |
| list_threat_modelsA | List saved threat models in the current workspace. Read-only; no side effects. Returns {items: [{id, title, version, created_at, ...}], count}. Use this to discover model IDs to pass to other tools, or for a portfolio overview. |
| rename_threat_modelA | Rename a threat model. Metadata change only, does not create new version. |
| set_threat_model_parentA | Set (or clear) a model's parent on the recursive composition tree. The composition substrate (Layer 0) builds an ancestor chain from
each model's parent_id so child models inherit topology, control
objectives, and other entities from their ancestors. Use this tool
when wiring a child model under a platform / system / shared-services
ancestor, or when re-rooting a model after a re-org. Pass parent_id=None to clear the parent (the model becomes a
tree root). The server rejects cycles (you cannot make a descendant
your parent) and over-deep chains (depth bounded by the platform's
configured maximum tree depth) with HTTP 400. Bumps the model version on
success. Returns the updated threat model. |
| declare_foundationA | Mark a model as a shared foundation that advertises providable controls. Mutating: records this model as a foundation and stores its advertised controls; other models can then delegate to them (see propose_attach_foundation / attach_foundation). A foundation is a shared service (auth, logging, a shared datastore) whose controls other models can rely on. Each entry in provides advertises one of THIS model's controls as providable: {"control_id": "CTRL-07", "capability_label": "Validates session tokens", "description": "..."}. A capability always advertises a control (a proven mechanism), never an objective. |
| list_relianceA | List a model's cross-model dependency edges, in both directions. Read-only; no side effects. Returns {model_id, as_consumer: [...], as_provider: [...]}. Consumer edges are this model's declared delegations / reliances on other models' controls; provider edges are other models relying on this one (its blast radius if its controls change). Use this to inspect existing dependencies before creating or deleting edges (create_reliance / attach_foundation / delete_reliance), or to understand what breaks if this model's controls change. |
| create_relianceA | Declare a cross-model dependency: this model relies on a provider control. Two modes (the target is ALWAYS a provider control — credit terminates at a
proven mechanism): delegated: this model does NOT implement an objective locally; it is
handled entirely by the provider's control. Pass source_objective_id.
relied_upon: this model has its OWN control whose validity depends on
the provider's control. Pass source_control_id.
The provider must be a model in the SAME workspace as the consumer (reliance
is workspace-scoped and does not reach across workspace boundaries). The edge
enters draft and runs LLM semantic validation; it carries no credit until
confirmed via confirm_reliance (and only when validation returned
valid). Returns the created edge. |
| confirm_relianceA | Promote a draft reliance edge to active (the credit-soundness gate). Refuses unless LLM validation returned valid. A partial result or a
mode mismatch is refused (never silently credited). Returns the updated edge. |
| delete_relianceA | Delete a cross-model reliance / delegation edge. Destructive and immediate. Mutating: permanently removes the edge. Any credit the consumer model derived from it (a delegated objective or a relied-upon control) is withdrawn, which can move the consumer's coverage/posture. Does not affect either model's own controls. Returns {deleted: True, edge_id}. Use list_reliance to find the edge_id first. To pause an edge without deleting, there is no toggle — deletion is the only removal path. |
| propose_attach_foundationA | Propose which of this model's objectives each foundation capability covers. Read-only: returns candidate (objective ↔ provider control) pairs with a
match score. Nothing is created or credited. Feed the chosen subset to
attach_foundation. |
| attach_foundationA | Create draft delegation edges for selected (objective, control) pairs. selections is a list of {"source_objective_id": ..., "provider_control_id": ...}
(typically the operator-confirmed subset of propose_attach_foundation).
Each becomes a delegated draft edge that runs LLM validation; none
carries credit until separately confirmed. Returns {created, failed}.
|
| delete_threat_modelA | Delete a threat model and all associated data. Destructive and permanent — cannot be undone. Mutating: removes the model along with every version, its controls, assertions, findings, attestations, and tag/reliance memberships. Reliance edges from other models that pointed at this one are invalidated, which can move those consumers' posture. Confirm intent before calling. To keep a copy first, use export_report (scope="model", format="archive") (a self-contained, re-importable JSON archive). Returns {deleted: True, model_id}. |
| get_threat_modelA | Get a specific threat model by ID. Returns the full threat model including trust boundaries, assets,
attackers, control objectives, and assumptions. Important for agents reading model state: Assets and attackers may carry deleted: true (soft-deleted).
Exclude these when showing "what's in the model now"; include
them only when discussing history or offering restore. Restore
an entity via restore_entity (entity_type="asset") / restore_entity (entity_type="attacker"). Control objectives may carry removed: true (tombstone — the
(asset, attacker) pair was removed in a later version). Exclude
these from coverage math and LLM prompts; they exist to keep
CO IDs stable so controls referencing them can be detected as
"orphaned" rather than silently rebinding.
|
| import_threat_model_archiveA | Import a JSON audit archive (from export_report (scope="model", format="archive"))
into a target workspace. Mutating: creates a NEW threat model in the target workspace. Requires
write access to that workspace. A fresh model_id is assigned on every
import, so the same envelope can be imported any number of times
without collisions; title collisions in the target workspace
auto-suffix (imported YYYY-MM-DD). Non-destructive — never
overwrites or touches an existing model. Use to move or clone a model between workspaces or across instances;
the envelope round-trips through export_report (scope="model", format="archive")
first. |
| get_control_generation_statusA | Poll the async control-generation status for a threat model. When generate_threat_model / refine_threat_model return a
controls_status other than complete, controls are being authored in
the background — poll this until a terminal state, then read the controls. Return shape: {status, mode, target_cos, ready_cos, error_message, elapsed_seconds} (or {status: "none"} when controls were built inline).
status is queued | generating | deferred | complete | failed | skipped | none: deferred — today's background-analysis budget is used up; generation
resumes automatically at the daily reset (relay this to the user).
failed — error_message says why (e.g. insufficient credits).
ready_cos / target_cos — coverage progress.
elapsed_seconds — time since queued; if it stays queued with a
large elapsed, generation may not be progressing — surface that instead of
polling forever.
Read-only; no side effects (polling does not trigger or alter generation). |
| regenerate_controlsA | Regenerate controls from the model's control objectives. Mutating. Re-authors controls from the current COs. Controls whose descriptions
survive regeneration unchanged KEEP their implementation status,
evidence, notes, assertions, and Jira / compliance mappings. Controls
whose descriptions change or disappear are soft-deleted (still
queryable via get_controls(include_deleted=True)). When co_ids
is given, only those COs' controls are regenerated — all other controls
are left as-is. May run as a background job; this tool waits for completion and returns
the final result. To rebuild everything, omit co_ids. To fix only
stale/orphaned CO mappings without re-authoring control text, prefer
remap_control (mechanical, no LLM). |
| update_control_statusA | Update the implementation status of a security control. Mutating. Sets the control's status to "implemented" or "not_implemented".
Marking a control "implemented" REQUIRES at least one assertion on the
control — check its assertion_count (via get_controls) first and
submit assertions with submit_assertions if it is zero, or the call
is rejected. |
| refine_controlA | Refine a control's description with AI-gated CO sufficiency check. Two modes: Provide description: proposes a new description directly. Provide codebase_findings: the platform proposes a description
based on existing code that may already satisfy the control. Both can be provided: the platform evaluates the proposed
description with the codebase findings as context.
The AI evaluates whether the mitigation group still collectively
satisfies all mapped control objectives. If rejected, returns
{accepted: false, reason, per_co} with per-CO reasoning. Side effect on accepted refinements: every assertion attached
to this control is superseded — their claims were authored against
the prior description and are not guaranteed to align with the new
one. The response includes superseded_assertions: <count> so
the caller knows how many. Re-submit any assertion that still
applies under the new description; superseded rows remain in
history with superseded_by="control_refined:...". |
| remap_controlA | Mechanical, non-AI-gated remap of a control's CO mappings. Distinct from refine_control (AI-gated description edit) and
set_mitigation_groups (AI-gated CO-centric group authoring).
Use remap_control when the operator already knows the correct
co_ids and just needs to persist the mapping change — e.g.,
restoring mappings after an asset/attacker edit left the control
with stale or orphaned CO references. No LLM evaluation runs. Rejects target co_ids that do not exist on the model or are
tombstoned (the pair was removed in a later version) — map to
live COs only. |
| apply_control_changesetA | Apply a batch of control operations atomically as ONE transaction. Use this to reorganize a model's controls in a single step — for example
to deduplicate controls (remap several onto the right objectives and delete
the redundant ones at once), instead of many separate calls. All operations
commit together or not at all. Mapping-only: remap/delete/set_groups change objective mappings and retire
controls but never re-author a control's description, so a kept or reused
control keeps its status, evidence, and assertions. The orphan guard is
evaluated on the FINAL state of the batch, so a delete paired with a
covering remap or add in the same changeset is allowed; a changeset that
would leave any previously-covered control objective uncovered is rejected
as a whole and nothing is written. |
| model_coherence_reportA | Static-analysis report on coherence between the model's
component declarations, the code-binding strings on its controls
and assertions, and the structural reachability of every CO. Pass co_id to scope the report to findings carrying that CO id
(the co_* reachability findings + the attestation cross-link
findings). Component- and assertion-level findings without a CO
binding are excluded in single-CO mode. 404 if the CO doesn't
exist on the model. The report carries up to twelve finding types, grouped below by
concern. Each finding includes the entity IDs it concerns
(co_id, asset_id, attacker_id, component_id, etc.)
so the agent can dispatch the resolution tool directly without
re-fetching the model. Component / assertion bindings: control_component_unknown — control references a component
ID that no longer exists. Resolve: assign_to_components (target_type="control").
asset_component_unknown — asset references a missing
component. Resolve: edit_asset (with corrected
component_ids).
assertion_repo_mismatch — an assertion's repo does not
match the repo_url of any component scoping its control.
Resolve: rebind the assertion or rescope the control.
assertion_repo_orphan — an assertion has a repo but its
control is unscoped. Resolve: assign_to_components (target_type="control")
to scope the control, or correct the assertion's repo.
control_unscoped_with_scoped_assertions — control is
unscoped, but its assertions all carry a single component's
repo. Resolve: assign_to_components (target_type="control") to that
component.
component_unbound — a component has no repo_url. Two
cases, told apart by the component's trust boundary. An
internal-zone component (your own code) that isn't linked yet:
resolve with edit_component pointing at the real repo. An
external-zone component (e.g. a third-party service, the
customer's IdP, or other external infrastructure you call but
don't own): leave it
unbound — the finding is a permanent, auditor-visible external-
dependency marker, NOT a TODO. Never bind an external component
to your repo to silence this; "some client code touches it" is
not a reason to bind (that client code lives in your repo for
every dependency).
Reachability findings (deterministic composer; indeterminate
verdicts surface as findings, never auto-decided by an LLM): co_attacker_unpositioned — the CO's attacker has no
positioned trust boundaries. Resolve: edit_attacker (set
trust_boundary_ids), or add_assumption with a
structured exclusion predicate.
co_asset_unbounded — the CO's asset has no component-derived
trust boundaries. Resolve: assign_to_components (target_type="asset"),
edit_asset (with component_ids), or add_assumption
with a structured exclusion.
co_no_shared_boundary — attacker and asset boundaries do
not intersect. Resolve: re-position the attacker via
edit_attacker, scope the asset to a shared component via
assign_to_components (target_type="asset"), or add_assumption with a
structured exclusion.
co_missing_entity — the CO references a missing
asset/attacker; model state inconsistent. Resolve: restore
the entity (restore_entity (entity_type="asset") / restore_entity (entity_type="attacker")) or
remove the orphaned CO via refine_threat_model.
Use this before relying on component-scoped control discovery,
when assertion verification fails for path/repo reasons, or to
enumerate structural-completeness gaps the operator should
address before treating the model as audit-ready. get_reachability_verdicts
exposes the underlying composer verdicts directly when the
finding-shape summary isn't enough. |
| get_composition_overviewA | Composition index for a model — counts, tree metadata, warnings. Read-only; no side effects. Cheapest call in the composition surface
(~1-2KB). Use it first to learn whether composition is available for
this model, where the model sits on the recursive tree (parent +
ancestor chain + child ids), how many own vs inherited entities and
COs there are per kind, and whether any structural warnings (cycle,
parent missing, max depth exceeded) need surfacing before drilling
into sub-resources. Return shape:: {
model_id, model_version, flag_enabled,
tree: {parent_id, ancestor_chain, depth, child_ids},
counts: {
entities: {kind: {own, inherited}, ...},
control_objectives: {total, live, covered, uncovered,
indeterminate, by_origin: {own, cross, inherited}},
reconciliation_candidates: {certain, heuristic},
},
warnings: [str, ...],
}
When composition is not available on the backend, the same shape is
returned with all counts zeroed and flag_enabled: false — detect
that rather than handling an error. |
| list_effective_entitiesA | Effective entity set (own ⊕ inherited) keyed by kind. Returns the entity set this model sees after composition with
ancestors: trust boundaries, components, assets, attackers, and
(when applicable) attack paths. Each entry carries its provenance —
whether it originates on this model or is inherited from an
ancestor — plus a fully-qualified id so cross-model references are
unambiguous. Pair with list_effective_control_objectives and
get_effective_coverage to see how inherited topology contributes
to coverage credit. Return shape:: {
model_id, flag_enabled,
kinds: {
trust_boundaries: [{kind, qualified_id, owner_model_id,
owner_title, origin, entity}, ...],
components: [...], assets: [...], attackers: [...], ...
},
total, page, page_size,
}
When composition is disabled on the backend, kinds is returned
with every kind mapped to an empty list and flag_enabled: false. Omitting page / page_size defaults to page=1, page_size=100 — the response is paginated and no longer returns
every entity in a single call. |
| list_effective_control_objectivesA | Effective control objectives with origin classification. Returns every CO visible on the effective model, each tagged with
its origin: own (authored on this model), cross (an inherited
CO whose asset or attacker is local to this model), or inherited
(purely inherited from an ancestor). Use this to see what control
objectives the model is on the hook for — including those it
inherits — before reading coverage or reach. Return shape:: {
model_id, flag_enabled,
control_objectives: [
{co_qid, asset_qid, attacker_qid,
security_properties: ["C"|"I"|"A"|"U", ...],
origin: "own"|"cross"|"inherited"},
...
],
}
When composition is disabled on the backend, returns an empty list
and flag_enabled: false. |
| get_effective_coverageA | Effective coverage rollup with credited inheritance. Read-only. Per effective CO: whether it is covered, how much credit
comes from controls owned by this model vs inherited from ancestors,
and the list of contributing controls (with the owning model id,
origin tag, verification status, and mitigation group). This is the
surface that drives the composition view's coverage / compliance
numbers — it reflects composed (own ⊕ inherited) math, NOT the
per-model coverage shown by get_verification_report. Return shape:: {
model_id, flag_enabled,
coverage: [
{co_qid, is_covered, own_credit, inherited_credit,
contributing_controls: [{control_id, owner_model_id,
origin, is_verified, mitigation_group}, ...]},
...
],
total, page, page_size,
}
When composition is not available on the backend, coverage is
empty and flag_enabled: false. Paginated: omitting page / page_size defaults to page=1, page_size=100 — a single call no longer returns every coverage row. |
| list_effective_attack_pathsB | Effective AttackPath set + lifted missing/dangling suggestions. AttackPaths inherit from ancestors with the same own / inherited
provenance as other entities. The suggestions block is the
missing-path / dangling-path delta computed against the composed
effective topology — a child sees the inherited baseline claims, the
composed reach surface, and the delta against both. Return shape:: {
model_id, flag_enabled,
effective_paths: [{kind, qualified_id, owner_model_id,
owner_title, origin, entity}, ...],
lattice_positions: int,
authored_paths: int,
suggestions: {missing_path: [...], dangling_path: [...]},
}
When composition is disabled on the backend, effective_paths is
empty, the counts are zero, suggestions is empty, and
flag_enabled: false. |
| apply_certain_reconciliation_matchA | Apply a certain-tier reconciliation candidate. Mutates state. Soft-deletes the descendant's own duplicate entity; the inherited
entity becomes the canonical surface for the effective-model
resolver. Use after surveying candidates via
list_reconciliation_candidates. Certain-tier candidates apply
directly; heuristic-tier candidates need operator review of the
structural divergence and are refused server-side unless
confirm_heuristic=True is passed to acknowledge the divergence. The server re-validates the candidate against current live state
before applying; if the model has moved since the candidate was
detected, returns 400 and the operator should refresh the candidate
list and retry. Bumps model version and emits an activity event on
success. |
| reject_reconciliation_candidateA | Reject a reconciliation candidate. Mutates state. Records the operator's "these are NOT duplicates" decision at org
scope so the candidate detector filters this pair out of the active
queue on subsequent reads. Idempotent on the natural key
(model_id, kind, own_qid, inherited_qid) — re-rejecting an existing
pair returns the same row. Use when list_reconciliation_candidates
surfaces a pair that looks like a duplicate but the operator has
confirmed it is not. Persistence is at org scope, not model state — the rejection is durable
across sessions and teammates but does NOT bump model version. |
| unreject_reconciliation_candidateA | Remove a persisted reconciliation rejection. Mutates state. The pair becomes eligible to surface in the active candidate queue
again on the next read of list_reconciliation_candidates. Use when
the operator changes their mind about a prior rejection — the surrogate
rejection_id comes from rejections[*].id on
list_reconciliation_candidates (disposition="rejected") (or the return value of
reject_reconciliation_candidate). Does NOT bump model version (rejection is org state, not model state). |
| lift_composition_entityA | Promote a shared-anchor entity from two sibling descendants to their
lowest common ancestor. Mutates state across THREE models. The operator has confirmed (via the composition lift-candidate view)
that the entity local_id_a on descendant_a_id and the entity
local_id_b on descendant_b_id are the same logical thing and
should be modeled once on the LCA. The route's model_id is the
operator's current context model — typically the LCA, but the server
accepts any ancestor of both descendants. Conflict resolution. The server re-detects field-level and
attached-state conflicts against current live state before applying.
If new conflicts have surfaced since the operator's last candidate
fetch, the call returns 400 with the missing conflict keys; refresh
the lift-candidate view and resubmit with resolutions covering every
key. Each entry in field_resolutions / attached_state_resolutions
is "keep_a" | "keep_b" | "keep_both" (union for list/set
fields; falls back to B for scalars). Over-application gate. The lift extends visibility to every descendant
of the LCA, not just the two source descendants. The server runs an
over-application gate that refuses lifts touching descendants outside
an acknowledged set; pass acknowledged_third_party_subtrees to
acknowledge specific subtrees, or skip_overapplication_gate=True to
override entirely after explicit operator confirmation. Each affected model (LCA + both descendants) bumps version and emits a
model_refined activity event; a structured lift_applied event
with the full lift_event payload lands on the LCA. The audit pack
surfaces this under lift_history. Reverse it with
undo_composition_event (event_type="lift") (preview first via
preview_undo_composition (event_type="lift")); the inverse operation is
split_composition_entity. |
| split_composition_entityA | Push an ancestor-owned entity down to one or more descendants and
soft-delete the ancestor's copy. Mutates state across the ancestor +
every target descendant. Inverse of lift_composition_entity. Use when an entity that
currently lives on an ancestor is in fact descendant-specific and
should be modeled separately per descendant — the operator chooses
which descendants take a copy. A new local id is minted on each
target; attached state on the ancestor's entity (assertions, jira
mappings, risk acceptances, etc.) is duplicated to every target. The route's model_id IS the ancestor (the entity being split lives
on it). Each affected model (ancestor + every target descendant) bumps
version and emits a model_refined activity event; a structured
split_applied event with the full split_event payload lands on
the ancestor. The audit pack surfaces this under split_history. |
| get_mitigation_groupsA | Get the current mitigation group structure for a control objective. Returns the grouped view of controls for this CO with details
(id, description, status) for each control: groups: numbered groups (within=AND, across=OR) defense_in_depth: tracked but not required for mitigation unmapped: model controls not mapped to this CO (available for assignment)
Use cases: Before set_mitigation_groups to see the current structure When reviewing a CO's assessment to understand why it is at_risk or mitigated When deciding which unmapped controls to assign to a CO
|
| set_mitigation_groupsA | Declaratively set the mitigation-group structure for a control objective. Mutating; runs as a polled background job (an LLM sufficiency check evaluates whether the new structure satisfies the CO) and returns once complete. Replaces ALL mitigation-group assignments for this CO. Call
get_mitigation_groups first to see the current structure and the
unmapped controls available for assignment. Mitigation groups define alternative paths to satisfy a CO: Within a group: AND — all controls must be implemented. Across groups: OR — any one complete group mitigates the CO. Defense-in-depth: tracked but not required for mitigation.
|
| add_evidenceA | Attach an auxiliary evidence item (doc, link, or artifact reference) to a control. Mutating. Evidence is contextual metadata only — it does NOT count toward a
control's implementation status; only assertions prove controls.
Use remove_evidence to detach an item. |
| remove_evidenceA | Remove one evidence item from a control by its position in the control's evidence array. Mutating. Evidence is auxiliary metadata (see add_evidence); removing it
does not affect the control's implementation status or any
assertions. To find the index, read the control via get_controls (control_id=...)
and count its evidence array from 0. |
| import_controlsA | Import existing security controls into a threat model. Accepts structured JSON or free-text. Controls are auto-mapped to COs and
deduplicated against existing ones. The parse/map/dedup runs as a background
job (polled for progress), then — because this mutates the model — you are
asked to confirm before the controls are saved. |
| delete_controlA | Soft-delete a security control, optionally with a justification. Destructive (mutating): the control is retired, not permanently erased. Blocks with HTTP 409 when the control is the ONLY control covering
any control objective — removing it would leave that CO uncovered.
Add a replacement control (or refine the threat model) before
deleting. |
| check_control_gapsA | Analyze control coverage and surface control objectives that lack sufficient controls. Read-only (does not mutate the model); runs as a polled background job and uses LLM reasoning. Complements the deterministic assess_model (which scores each
CO's mitigated / at_risk / unassessed status from control
implementation state) by reasoning about which COs are under-covered
and where new controls are needed. Use this to decide what controls
to add; use assess_model to score the current state. |
| assess_modelA | Run the deterministic assurance assessment over a threat model. Read-only — no LLM calls, no mutation. Evaluates each control objective from its controls' implementation
status and returns summary counts (mitigated / at_risk /
unassessed) plus progressive metrics (defined / implemented /
verified). For LLM-based reasoning about which COs are
under-covered and what controls to add, use check_control_gaps
instead. Use summary_only=True to get just the counts without per-CO
assessments. |
| get_review_queueB | Returns controls not reviewed in 90+ days. Lists implemented/verified controls whose assertions have not been checked
recently. For each stale control, verify assertions against codebase. |
| add_assetA | Add a new asset to a threat model. Creates a new version. Authoring contract: name the data or resource being
protected and the security property at stake (Confidentiality /
Integrity / Availability / Usage) — not a mechanism, control, or
capability. Name the thing whose exposure or corruption is the
harm (e.g. "per-organization key-wrapping material", not "KMS
encryption"). An asset phrased as a mechanism is flagged with a
quality_warning and the control objectives derived from it may
be under-specified. The caller supplies identity-bearing fields (name, description,
security_properties, notes) plus optional component scoping; the
backend LLM-reasons the factor decomposition (and composes the
impact rating from it). The same prompt the generation
pipeline uses for LLM-produced assets is reused here, so factors
are calibrated consistently regardless of who introduced the
asset. Override any factor post-create via edit_asset with a
change_reason for the audit trail. component_ids (optional) links the asset to one or more
deployable units. Components are the canonical bridge between
security architecture (trust boundaries) and code organization
(repos); linking assets here flows boundary context into the
reachability graph. Multi-component is the right shape for
multi-instance assets (e.g., a session token on client + cache).
LLM-gated against a re-add of a previously soft-deleted asset on
the same model. Three possible outcomes: Normal create — fresh asset with a new ID. Returns the
envelope {"model": ThreatModel, "controls_carried": N, ...}. Auto-restore — proposal matched a soft-deleted asset; that
asset is un-deleted (CO tombstones revive). Response carries
auto_restored: True, restored_asset_id, and
discarded_fields. Similar-verdict rejection — {"accepted": False, "classification": "similar", "candidate_restore_id": "A-N", ...}; nothing saved.
Fails with a tool error on: |
| edit_assetA | Edit an existing asset. Only provided fields changed. When changing identity fields, hold to the asset authoring
contract: name the data/resource protected and its security
property, not a mechanism — otherwise the result is flagged with a
quality_warning (see add_asset). The composed impact is server-derived from the factor fields;
there is no way to set it directly. To change the rating, set
factor values (the platform composes the new rating) and supply
change_reason documenting the operator override of the
LLM-generated factors. The reason is captured in the
rating-revision audit trail. LLM-gated on identity-bearing fields (name, description,
security_properties). Factor and notes edits skip the gate. Outcomes when identity fields change: Accepted edit (LLM classifies as preserve) — normal
envelope response. Rejected edit (LLM classifies as replace /
ambiguous) — {"accepted": False, ...}; nothing saved.
Soft-delete + add-new instead.
Editing a soft-deleted asset is rejected — restore_entity (entity_type="asset")
first. 503 on evaluator outage, 502 on malformed response, 400
when factor fields are sent without change_reason. |
| add_attackerA | Add a new attacker to a threat model. Creates a new version. Authoring contract: capability names the operations the
attacker can perform from its position and what they achieve —
not just the access or vantage point. Phrase it as "From
[position], the attacker can [concrete operations] …" (e.g. "From
the network path between the API server and the database, the
attacker can read and alter requests and responses to exfiltrate
data in transit or inject forged responses"). A capability that
states only access is flagged with a quality_warning and the
control objectives derived from it may be under-specified. The caller supplies identity-bearing fields (capability, position,
archetype, trust_boundary_ids); the backend LLM-reasons the factor
decomposition. Override any factor post-create via edit_attacker
with a change_reason. Mirror of add_asset semantics. Three outcomes (normal create / auto-restore / similar-rejection)
mirror add_asset. 503 on factor-reasoning or restore-candidate
evaluator outage, 502 on malformed restore-candidate response. |
| edit_attackerA | Edit an existing attacker. Only provided fields changed. When changing identity fields, hold to the attacker authoring
contract: capability names the operations performable from
the position ("From [position], the attacker can [operations] …"),
not just access — otherwise the result is flagged with a
quality_warning (see add_attacker). The composed likelihood is server-derived from the factor
fields; to change the rating, set factor values and supply
change_reason for the audit trail. LLM-gated on identity-bearing fields (capability, archetype,
position). Factor and trust_boundary edits skip the gate. 503 on evaluator outage, 502 on malformed response, 400 when
factor fields are sent without change_reason. |
| reevaluate_threat_model_factorsA | Re-run the LLM factor judgment on every asset and attacker in
a threat model. Useful for re-baselining factors after a bug fix
or feature-description change, without regenerating the whole
model (which would destroy controls, assertions, components). Each entity's factors and rationale are replaced with a fresh
LLM-judged decomposition; the composed impact / likelihood is
re-derived deterministically from the new factors. Each re-rating
is recorded as a rating revision in the audit trail with
change_reason (default: "LLM factor re-evaluation") so the
starting-point regeneration is distinguishable from operator-
supplied factor overrides via edit_asset / edit_attacker. The platform's LLM factor judgment is a starting point. For
deployment-specific factor adjustments (e.g., elevated
regulatory_scope because your tenant is HIPAA-covered, or
Commodity prevalence because your endpoint is public-internet
exposed), use edit_asset / edit_attacker afterward with a
change_reason documenting the operator override. Per-entity soft-fail: an LLM failure on one entity is recorded in
the response's failed_entities list (with id, kind, and
reason); the remaining entities are still re-evaluated and
their rating revisions persisted as they complete. The endpoint
returns 503 only when every live entity failed — in which case
nothing was persisted; retry when the evaluator is reachable. Soft-deleted assets and attackers are skipped. |
| get_verdict_divergenceA | Where the LLM's verdicts disagree with the model's authored state. Two coverage divergence kinds, distinguished by the LLM's p_covers
(probability the control covers the CO), shown as "model confidence": missing_mapping: HIGH p_covers, but the CO is NOT mapped — the LLM
is confident the control covers it, so it should be mapped. Accepting
ADDS the mapping.
spurious_mapping: LOW p_covers, but the CO IS mapped — the LLM is
confident the control does NOT cover it, so the mapping is likely wrong
and inflates apparent coverage. Accepting REMOVES the mapping.
Only confident rows surface; the uncertain middle band is dropped. So a
~100%-confidence row is a strong "add" and a ~0%-confidence row is a strong
"remove" — both are actionable, in opposite directions.
Rows are sorted by confidence, so the strongest calls come first. Each
section is paginated: its pagination.filtered_total reports the full
count, so when it exceeds the rows returned, raise limit (up to 500) or
page with offset to review every divergence — not only the first page. Also returns group_sufficiency divergences (observation-only). Apply
coverage rows with accept_coverage_divergences; set aside rows the
structural model got right with dismiss_verdict_divergences. |
| accept_coverage_divergencesA | Accept a set of coverage divergences as mapping changes, in one batch. Each accepted missing_mapping ADDS its CO to the control; each
spurious_mapping REMOVES it. Applied as one version per affected
control. Each item is validated independently — the response separates
applied from skipped (stale / would-orphan / already in that
state), so a partial batch still lands its valid items. Read the rows first with get_verdict_divergence; to accept only the
high-confidence ones, filter its coverage rows by p_covers (near 1.0
for missing_mapping, near 0.0 for spurious_mapping) before passing them
here. |
| dismiss_verdict_divergencesA | Dismiss a set of divergences (the structural model was right, the LLM
was not) WITHOUT changing the model. Use for rows you have reviewed and judged not valid. A dismissal is keyed
to the divergence's current verdict input hash, so it auto-clears (the row
reappears) once the underlying control or objective changes. Works for
coverage AND group_sufficiency rows. |
| retry_verdictsA | Re-trigger a model's parked verdict re-evals after a transient failure. When a verdict re-evaluation fails transiently — a provider outage,
exhausted credits, or a timeout — it is parked and reads as "unavailable /
treated as unverified", recovering only after a delay. This forces an
immediate, non-destructive re-run of ONLY the parked/failed re-eval slots,
across every verdict kind (coverage, group-sufficiency, per-control
sufficiency, coherence). It changes no assertions, controls, or verdict
content, so no IDs churn. Evaluation runs in the background — re-read the
sufficiency or verification report shortly after to see updated verdicts. Prefer this over recompute_verdicts when verdicts are stuck due to an
outage: recompute_verdicts force-enqueues coverage + group-sufficiency
for the whole model (metered per its estimate) and cannot un-park a job
whose inputs are unchanged, whereas this re-arms exactly the failed slots
and covers per-control sufficiency + coherence too. |
| list_compliance_frameworksA | List the compliance frameworks available to map controls against. Read-only; no side effects. Returns both built-in frameworks (e.g. OWASP
ASVS) and any custom frameworks in the workspace. Use this to discover
framework identifiers before select_compliance_frameworks (activate one
for a model) or import_compliance_framework (add a custom one). Takes no
arguments beyond the version guard. |
| import_compliance_frameworkA | Import a custom compliance framework. Requires PRO tier. Use this when your customer's program (regulatory, contractual, or
internal) is not covered by Mipiti's 11 built-in frameworks. After
import, the framework is selectable on threat models exactly like
a built-in. Schema (top-level fields):
- name (required): framework display name
- version (optional): e.g. "1.0"
- description (optional): one-paragraph description
- level_definitions (optional, level-aware frameworks only):
map keyed by stringified integer level ("1", "2", …)
because the key IS the cumulative-filter ordinal
(level <= target_level) and the level: int field on
every requirement. Non-integer keys are rejected with
HTTP 400. Human labels are decoupled — "Baseline" /
"Hardened" / "SL3" / "CAL Critical" live in the name
field, not the key. Each value is
{"name", "description", "source"}. Ships the per-level
legend to the LLM prompt and the framework-target UI.
source is "authoritative" when paraphrased from the
published standard, "mipiti_convention" when you defined the
tiers yourself.
- requirements (required, non-empty list): each entry takes
id (required), description (required),
level (optional integer, default 1),
chapter_id / chapter_name / section_id /
section_name / title (optional grouping),
scope (optional, "component" default or "system" for
requirements covered if ANY model satisfies them),
level_specific_text (optional map of per-tier text;
same stringified-integer-key rule as level_definitions). Example minimal body:: {
"name": "ACME Internal Baseline",
"version": "2026.1",
"requirements": [
{"id": "ACME-1", "description": "All endpoints authenticate", "level": 1},
{"id": "ACME-2", "description": "TLS 1.3 in transit", "level": 1}
]
}
Example with per-level legend + per-requirement parameters:: {
"name": "ACME Tiered",
"level_definitions": {
"1": {"name": "Baseline", "description": "Minimum.",
"source": "authoritative"},
"2": {"name": "Hardened", "description": "Sensitive data.",
"source": "mipiti_convention"}
},
"requirements": [
{"id": "ACME-PWD",
"description": "Passwords meet policy",
"level": 1,
"level_specific_text": {
"1": "Min 8 characters.",
"2": "Min 14 + MFA required."
}}
]
}
|
| map_control_to_requirementA | Manually map one security control to one compliance-framework requirement. Mutating: records a control-to-requirement mapping, which re-derives that requirement's coverage in the compliance report. Use for a single, deliberate mapping you are asserting by hand. To let the LLM propose mappings across many requirements at once, use auto_map_controls; to close gaps end-to-end (map + exclude + fill), use auto_remediate_compliance. |
| auto_map_controlsA | LLM-map a model's existing controls to a framework's requirements. Requires PRO tier. Mutating: writes control-to-requirement mappings. Runs as a background job (typically 20-45s); this tool waits for completion and returns the result. Sits between the manual map_control_to_requirement (one mapping at a time) and the full auto_remediate_compliance loop (which also excludes non-applicable requirements and proposes new entities for remaining gaps). auto_map_controls only creates mappings from controls that already exist — it never adds or excludes entities. |
| list_workspacesA | List the workspaces the current user belongs to. Read-only; no side effects. Returns each workspace's id and name. Models,
controls, and compliance are all scoped to a workspace, so use this to
discover the workspace context you're operating in. Takes no arguments
beyond the version guard. |
| update_organizationA | Set per-organization level grades for IEC 62443-4-1 and NIST CSF. Admin-only: the backend requires the caller to be an admin in the
organization (or a superadmin). Non-admins will get a 403; do not
invoke this tool unless you've verified admin role for the target
org. target_ml is the IEC 62443-4-1 Maturity Level the organization
targets for its secure-development program (1-5). csf_tier is
the NIST CSF Tier the organization targets for its cybersecurity
risk-management posture (1-4).
Because None on the wire is indistinguishable from "field
omitted", pass clear_target_ml=True or clear_csf_tier=True
to explicitly reset a value to NULL. Omitting both the value and
its clear_* flag leaves the existing server-side value
untouched. |
| add_componentA | Add a component to a threat model. Components bridge security architecture to code organization. They
map trust boundaries to repos so controls can be scoped to the
codebase that implements them. They also drive the deterministic
reachability composer's asset-boundary derivation: an asset's
trust-boundary footprint is the union of its components'
trust_boundary_ids. A component with empty repo_url is either speculative (your own
code, not linked to a repo yet) or external (e.g. a third-party
service, the customer's IdP, or other external infrastructure you
call but don't own).
The component's trust boundary tells them apart: bind an
internal-zone component to its repo via edit_component; leave an
external-zone component unbound — its component_unbound finding
is a permanent external-dependency marker, not a gap to close.
Binding by "some client code touches it" is wrong: client code for
external dependencies lives in your repo too. |
| edit_componentA | Edit a component's properties. Per-component level grades are orthogonal axes — set whichever
apply to the program the component is in scope for. Leave a field
unset (None) to keep the current server-side value; backend
treats absent fields as "unchanged". |
| get_system_dependenciesA | Get the cross-model dependency graph for a system. Read-only; no side effects. Returns every assumption in the system's member models that is linked to another member model (a cross-model dependency), with its satisfaction status. A dependency is satisfied when either the target model's mapped controls are implemented or a valid manual attestation exists. Use to see which assumptions are met by other models' controls, find unsatisfied dependencies, or check system-level completeness. Create these links with link_system_dependency. |
| submit_assertionsA | Submit assertions for a security control or an assumption. Mutating: persists new assertion records against the target. It does NOT run verification itself — assertions are checked later in CI (structurally, then semantically) and cryptographically attested; submitting only records the claims to be verified. To read existing assertions use list_assertions; to remove one use delete_assertion. Each assertion is a typed, machine-verifiable claim about a system property (source code, configuration, infrastructure, or external service settings). Provide exactly one of control_id or assumption_id: control_id: proves a control is implemented (e.g., "CTRL-01") assumption_id: proves a system property claim (e.g., "AS5" — asset non-applicability, attacker non-applicability, scope decisions)
For assumption assertions against the feature description (greenfield), use target instead of file in params:
{"type": "pattern_matches", "params": {"target": "feature_description", "pattern": "password.*TOTP"}, "description": "..."} Args:
model_id: ID of the threat model.
control_id: ID of the control (omit if using assumption_id).
assumption_id: ID of the assumption (omit if using control_id).
assertions_json: JSON array of assertion objects. Each object has:
- type (required): one of the assertion types below
- params (required): type-specific parameters (file or target + pattern/name/etc.)
- description (required): human-readable explanation of what this proves
- repo (optional): "org/repo-name" for multi-repo setups Assertion types: function_exists: Check that a function or method exists in a file. Supports Python, JavaScript, TypeScript, Go, Rust, Swift, Java, C#. Params: file (File path relative to project root), name (Function or method name) class_exists: Check that a class, struct, or interface exists in a file. Params: file (File path relative to project root), name (Class, struct, or interface name) decorator_present: Check that a decorator is applied to a function (Python). Params: file (File path relative to project root), function (Function name), decorator (Decorator name (without @)) function_calls: Check that a function calls another function. Params: file (File path relative to project root), caller (Calling function name), callee (Called function name) import_present: Check that a module is imported in a file. Supports Python, JavaScript, Go, Rust. Params: file (File path relative to project root), module (Module or package name) file_exists: Check that a file exists at the given path. Params: file (File path relative to project root) file_hash: Check that a file's hash matches an expected value. Use scope_file/scope_start/scope_end to reference the code that pins this hash (e.g., a deploy script that verifies the file's integrity). Params: file (File path relative to project root), algorithm (Hash algorithm: sha256, sha384, sha512, md5), expected_hash (Expected hex-encoded hash), scope_file (File containing code that references/checks this hash. Tier 2 reviews this code to verify the hash check is meaningful.); optional: scope_start (Regex marking start of the relevant code section in scope_file.), scope_end (Regex marking end of the relevant code section in scope_file.) pattern_matches: Check that a regex pattern exists in a file. Uses RE2 syntax (no backreferences, lookahead, or lookbehind). Params: file (File path relative to project root), pattern (RE2 regex pattern to search for); optional: scope_start (Regex pattern marking the start of the search scope within the file. Only content between scope_start and scope_end is searched.), scope_end (Regex pattern marking the end of the search scope. Defaults to end of file if omitted.), multiline (If true, ^ and $ match line boundaries instead of string boundaries. Default: false.), dotall (If true, . matches newlines, enabling patterns that span multiple lines. Default: false.) pattern_absent: Check that a regex pattern does NOT exist in a file. Uses RE2 syntax (no backreferences, lookahead, or lookbehind). Params: file (File path relative to project root), pattern (RE2 regex pattern that must be absent); optional: scope_start (Regex pattern marking the start of the search scope within the file. Only content between scope_start and scope_end is checked for absence.), scope_end (Regex pattern marking the end of the search scope. Defaults to end of file if omitted.), multiline (If true, ^ and $ match line boundaries instead of string boundaries. Default: false.), dotall (If true, . matches newlines, enabling patterns that span multiple lines. Default: false.) no_plaintext_secret: Check that no plaintext secrets matching given patterns exist in a file. Patterns use RE2 syntax (no backreferences, lookahead, or lookbehind). Params: file (File path relative to project root), patterns (JSON array of regex patterns to check for secrets) config_key_exists: Check that a config key exists. Supports JSON, YAML, TOML, INI, .env files. Use dot notation for nested keys. Params: file (File path relative to project root), key (Config key (dot notation for nested)) config_value_matches: Check that a config value matches a regex pattern. Uses RE2 syntax (no backreferences, lookahead, or lookbehind). Params: file (File path relative to project root), key (Config key (dot notation for nested)), pattern (RE2 regex pattern the value must match) env_var_referenced: Check that an environment variable is referenced in a file. Detects os.environ, process.env, ${VAR}, $VAR, etc. Params: file (File path relative to project root), variable (Environment variable name) dependency_exists: Check that a package exists in a dependency manifest. Supports requirements.txt, package.json, Cargo.toml, go.mod, pyproject.toml, pom.xml. Params: manifest (Path to dependency manifest file), package (Package name) dependency_version: Check that a package version satisfies a constraint. Uses PEP 440 syntax for Python, semver for JS. Params: manifest (Path to dependency manifest file), package (Package name), constraint (Version constraint (PEP 440 or semver)) parameter_validated: Check that a function validates a specific parameter. Tier 1 checks existence, tier 2 uses AI to verify validation logic. Params: file (File path relative to project root), function (Function name), parameter (Parameter name that should be validated) error_handled: Check that a function has error handling (try/catch/except, Go error checks, Rust Result). Params: file (File path relative to project root), function (Function name) middleware_registered: Check that middleware is registered in a file. Detects .use(), .add_middleware(), @decorator patterns. Params: file (File path relative to project root), middleware (Middleware name or class) http_header_set: Check that an HTTP header is set or referenced in a file. Params: file (File path relative to project root), header (HTTP header name) test_exists: Check that test files matching a glob pattern exist. Params: pattern (Glob pattern for test files) test_passes: Run tests matching a pattern and verify they pass. Auto-detects pytest, npm test, cargo test. Params: pattern (Test name or pattern to match) module_exists: Check that a Verilog/SystemVerilog module (or primitive/program) is declared in a file. Params: file (File path relative to project root), name (Module name) module_instantiated: Check that a module directly instantiates another module inside its module...endmodule body. Params: file (File path relative to project root), parent (Enclosing module name), child (Instantiated module name) port_exists: Check that a module declares a port, optionally with a specific direction. Detects ANSI header and non-ANSI body declarations. Params: file (File path relative to project root), module (Module name), port (Port name); optional: direction (Port direction: input, output, or inout) parameter_defined: Check that a parameter or localparam is declared, optionally that its assigned value matches a regex (RE2 syntax). Params: file (File path relative to project root), parameter (Parameter or localparam name); optional: module (Module to scope the search to (whole file if omitted)), pattern (RE2 regex the assigned value must match) signal_exists: Check that a net or variable (wire, reg, logic, bit) is declared. Params: file (File path relative to project root), name (Signal name); optional: module (Module to scope the search to (whole file if omitted)), kind (Declaration kind: wire, reg, logic, or bit) sva_assertion_present: Check that a named SystemVerilog assertion is present: a property declaration, or a labelled assert/assume/cover statement. Params: file (File path relative to project root), name (Property name or assertion label) register_reset: Check that a register is assigned on a reset path. Tier 1 finds an always block that references the reset and assigns the signal; tier 2 uses AI to verify the register resets to a safe, known value. Params: file (File path relative to project root), signal (Register/signal name that must be reset); optional: reset (Reset signal name (common rst/reset names detected if omitted))
|
| list_assertionsA | List active assertions for a control or assumption. Provide exactly one of control_id or assumption_id. Returns a flat list of assertions. Each assertion carries an origin
field: "own" for assertions submitted directly against this model's
control or assumption, "inherited" for assertions contributed through
model composition (composed models whose assertions apply here).
Inherited assertions are included in the listing. |
| delete_assertionA | Permanently delete a single assertion from a control or assumption. Mutating and destructive: the assertion record is removed, not soft-deleted, and its contribution to sufficiency/verification is dropped. It does NOT itself re-run verification; sufficiency is re-evaluated on subsequent reads. Use to retract a claim that was submitted in error or that get_verification_report flagged as misaligned (off-topic for the control's current description). To add assertions use submit_assertions; to inspect them first use list_assertions. Only "own" assertions can be removed here — inherited assertions come from composed models and must be managed on their source model. |
| get_verification_reportA | Get verification report with summary stats and sufficiency gaps. Returns tier1/tier2 pass/fail/pending counts, per-control verification
status, and sufficiency details. Each per-control sufficiency block carries: status: "sufficient" | "insufficient" | "pending" | "stale".
"stale" means the cached verdict no longer reflects the current
control description or active assertion set; a background
re-evaluation has been triggered automatically on this read — call
this tool again shortly for a refreshed verdict.
details: human-readable LLM reasoning.
misaligned_assertion_ids: assertions whose stated subject is
off-topic for the control's current description (common after a
control has been refined or regenerated). Treat as a directive:
rebind to the right control, supersede via delete_assertion,
or rewrite. Do NOT treat them as evidence. A non-empty list forces
the verdict to "insufficient".
stale: boolean shortcut for status == "stale", kept distinct
so an INSUFFICIENT verdict that's also stale (the prior insufficient
decision was computed under outdated inputs) can be flagged without
overloading status.
By default returns summary only (no per-assertion details). Set
summary_only=False to include full assertion details and drift items. |
| get_sufficiencyA | Sufficiency verdict for a single control: whether its submitted assertions collectively cover every aspect of the control. Read-only. Returns the LLM sufficiency status and reasoning for one control, evaluated server-side from the current assertion set (no CI round-trip). Use this for a focused check on one control after submitting assertions; for the whole-model rollup with tier1/tier2 pass/fail counts and drift/misalignment details across all controls, use get_verification_report instead. A verdict may be reported as stale when the control description or assertion set changed since it was last computed, in which case a fresh evaluation is triggered automatically — call again shortly for the updated result. |
| submit_findingsA | Record negative findings (gaps discovered while scanning a codebase against a model's controls). Mutating: persists new finding records against the model. Use after a gap-discovery scan (see get_scan_prompt) to log where expected control evidence was NOT found. Findings are the negative counterpart to assertions (positive proof via submit_assertions): a finding says "I looked here for this and it was missing." Once submitted, drive a finding through its lifecycle with update_finding and review them with list_findings. |
| list_findingsA | List negative findings recorded on a threat model. Read-only. Returns finding rows with their lifecycle status; use to triage gaps or to find a finding_id for update_finding / preview_finding_remediation. Each row carries an origin ("own" for findings recorded on this model, "inherited" for findings contributed through model composition, with inherited_from_* context); inherited findings are included in the listing. |
| update_findingA | Advance a finding through its lifecycle. Mutating: updates the finding's status and metadata. Use to acknowledge, remediate, verify, or dismiss a finding previously recorded by submit_findings / list_findings. This records a manual status transition; for gaps whose kind has an automatic fix, preview_finding_remediation + apply_finding_remediation perform the actual cleanup instead. |
| preview_finding_remediationA | Preview what the platform would do to remediate a finding. Read-only. Returns a structured diff describing the changes a
subsequent apply_finding_remediation call would make. Use this
BEFORE apply_finding_remediation to show the operator exactly
what cleanup will happen, and get explicit confirmation before
committing. The exact shape of the diff depends on the finding's kind. For
kind=structural_duplicate_controls, you get back which controls
would be kept, which dropped, and the union of CO mappings +
framework refs that would land on the survivor. Returns 404 if the finding doesn't exist; 422 if the finding's
kind has no automatic remediation handler. |
| apply_finding_remediationA | Apply the remediation for a finding. Mutates state. Commits the changes preview_finding_remediation showed. The
justification is recorded in the audit trail and shown in any
future review of why this cleanup was run. DO NOT call this without first calling
preview_finding_remediation and showing the operator the diff.
The agent's role is to surface what's about to happen and get
explicit operator confirmation; the platform records who acted
but doesn't enforce the preview-then-apply norm — the agent does. Returns 404 if the finding doesn't exist; 409 if the finding is
already remediated or dismissed; 400 if justification is empty;
422 if the finding's kind has no automatic remediation handler. |
| get_findings_risksA | Workspace-scoped triage dashboard: open findings, active risk
acceptances, and at-risk Control Objectives across every model
the workspace can access. Use this as the entry point when an operator asks "what's open?"
or "what should I work on next?" — one round-trip returns all
three categories with model context and risk dimensions
(severity, status, risk_tier, owner, review_by) so the agent can
triage without per-model fan-out. The endpoint is read-only and
fast; it composes from existing per-model queries server-side. Returns the envelope verbatim: {workspace_id, evaluated_at, models, findings, risk_acceptances, at_risk_cos, summary}.
summary carries totals (open_findings, total_findings,
active_risk_acceptances, total_risk_acceptances,
at_risk_cos) for quick health-check responses. |
| get_remediation_leverageA | Remediation-leverage plan for a model: which controls to implement
first to close the most control objectives with the least work. Returns the model's not-yet-satisfied controls ranked by how many
control objectives each one closes (ranked), plus a greedy
minimal fix order — the sequence of controls that reaches the most
mitigated objectives with the fewest controls (greedy_plan) — and
a summary of the collapse (total objectives, currently mitigated,
how many controls the plan needs). Use to prioritize implementation
work: a single call tells the agent which controls give the highest
leverage, so it can tackle the shortest path to coverage instead of
fixing objectives one at a time. Read-only. Composed models: each entry in ranked and greedy_plan also
carries its owning model — owner_model_id and owner_model_title
— and an inherited flag. inherited is true when the control is
authored on an ancestor model, meaning the fix lands on that model
rather than the one being assessed; summary.inherited_candidate_controls
counts them. Surface the owning model so the operator knows which
high-leverage fixes belong to a parent model. A flat (non-composed)
model reports every control as owned by the assessed model. |
| list_risk_acceptancesA | List all risk acceptances on a specific threat model — risks
that an operator explicitly accepted instead of mitigating. Each entry carries the CO id, owner, justification, status
(active / expired / revoked), and the review
deadline. Use to inspect which gaps were intentionally accepted
versus genuinely unaddressed when triaging at-risk COs. |
| create_risk_acceptanceA | Record that an operator explicitly ACCEPTS the residual risk on a control
objective instead of mitigating it — the write counterpart to
list_risk_acceptances. Use when a control objective's residual risk is a deliberate, documented
decision rather than an unaddressed gap: the acceptance carries an owner, a
justification, and a review deadline, and reads as active until it
expires or is revoked. Prefer this over leaving a known-and-accepted risk
implicit — it makes the decision auditable and forces a revisit by the
deadline. An accepted objective is still surfaced (as accepted, not
unaddressed) when triaging at-risk objectives. |
| complete_setup_stepA | Mark one onboarding setup step as done. Mutating: updates the workspace onboarding checklist. Call after actually performing the corresponding setup action on the user's behalf. Check current progress with get_setup_status first to avoid re-marking completed steps. An unrecognized step_id is rejected without any state change. |
| get_setup_statusA | Get the workspace onboarding checklist with completed and pending steps. Read-only. Call this before suggesting or performing setup actions so already-done steps aren't repeated; mark a step done with complete_setup_step. Takes no arguments beyond the version header. |
| add_trust_boundaryC | Add a trust boundary. Creates a new model version. |
| edit_trust_boundaryA | Edit a trust boundary. Creates a new model version. |
| add_assumptionA | Add an assumption. Creates a new model version. Assumptions represent security properties outside the system owner's
trust boundary. When linked to COs and attested, they mitigate those
COs in the assessment. Optionally attach a structured exclusion predicate (the
exclusion_* params). The reachability composer matches active attested assumptions with predicates against COs deterministically
— class-3 (deterministic computation) evidence in addition to the
operator-attested class-1 evidence. Pass any subset of the fields;
unspecified fields default to wildcard ("*"). When
exclusion_co_ids is non-empty, it takes precedence over the
match fields.
Use this to resolve a CO whose composer verdict is
indeterminate because no structural primitive backs an
operator non-applicability claim: set exclusion_co_ids=<co_id>
(and optionally the attacker/asset/property fields), and the
composer will derive unreachable / reason: assumption_excludes
on subsequent loads, with the assumption's structured predicate as
the audit-trail cause. |
| edit_assumptionA | Edit an assumption. Creates a new model version. |
| submit_attestationA | Record that a responsible party affirmed an assumption holds. Only for external assumptions. Non-applicability assumptions
require CI verification (submit assertions + run mipiti-verify) — manual
attestation is rejected for them. An assumption with a current attestation can mitigate linked COs.
When the attestation expires, those COs become at-risk until
re-attested or covered by controls. |
| list_attestationsA | List an assumption's attestation history. Read-only; no side effects. Returns the chronological record of attestation events recorded against the assumption (each with its actor, timestamp, and status/expiry as recorded), so you can trace why the assumption is currently attested, expired, or never attested. An assumption only mitigates its control objectives while it is active AND currently attested, so use this to diagnose coverage that depends on an attestation. To record a new attestation use submit_attestation; for the assumption's current fields (status, description) use get_entity (entity_type="assumption"). |
| get_control_assumption_groupsA | Get the current assumption group structure for a control. Assumption groups define alternative sets of external claims that can
satisfy a control: |
| set_control_assumption_groupsA | Declaratively set the assumption group structure for a control. Replaces all assumption group assignments for this control. Each group
is a set of assumption IDs that together externally handle the control;
any one group being fully active+attested is sufficient. Within a group: AND — all referenced assumptions must be active and
attested for the group to count as complete Across groups: OR — any one complete group marks the control as
externally handled for mitigation purposes
To clear all assumption groups (revert to "not externally handled"),
pass an empty JSON object: {}. AI relevance gate (per group, no override):
Each non-empty proposed group is evaluated independently. The behavior
depends on how many groups pass: All groups accepted → 200 success, structure persisted as submitted. Some groups accepted (partial): the accepted groups ARE persisted
(runtime OR-semantics activate immediately), the rejected groups
are NOT saved, the call raises with HTTP 422 detailing both
persisted_groups and rejected_groups (with per-group reasoning).
Resubmit only the rejected groups with assumptions that cover the
control, or sharpen those assumptions' descriptions. All groups rejected: existing groups on this control are
re-evaluated through the same gate. Relevant existing groups are
preserved; irrelevant existing groups are dropped (assumptions
themselves remain in the model — only this control's linkage is
removed). The call raises with HTTP 422 detailing what was
persisted, what was rejected, and what existing was dropped. Empty submission ({}): clears all groups, no evaluation.
There is no force-override. To get a group accepted, choose assumptions
whose descriptions actually cover the control or refine an assumption's
description so coverage is explicit. |
| convert_assumption_to_controlsA | Convert a violated or retired assumption to controls. Generates controls for the COs that were covered by this assumption,
then retires the assumption's CO linkage. Use when an assumption is
no longer valid and the system owner needs to implement controls
instead. Side effect on control-level linkage: this assumption is also removed
from every assumption_groups entry on every control that referenced it.
Any group left empty by the removal is dropped, and any control that
no longer has at least one complete group reverts to not_implemented.
Underlying assumptions are not deleted — only the linkages. |
| generate_functional_objectivesA | Derive capabilities, functional objectives, and the concrete tests to
implement from the feature spec. Capabilities are the behaviours the feature must deliver; each is walked
against a taxonomy of operating conditions (nominal, boundary, invalid
input, dependency failure, concurrency, …) to produce testable
Given-When-Then objectives — and then a concrete, implementable test is
specified for each objective (so the agent implements the tests rather than
deciding what to test). Requires a Pro plan. Billable — may take some time.
refresh=true re-derives from scratch, replacing prior generated (not
manually authored) capabilities, objectives, and tests. |
| list_capabilitiesA | List every capability (a behaviour the feature must deliver) for a model. Read-only; no side effects. Use this to enumerate a model's capabilities
(e.g. before reviewing functional objectives). To fetch one capability's
full detail use get_capability instead. |
| get_capabilityA | Get one capability with its component and asset bindings. Read-only; no side effects. Use when you already have a capability_id
(e.g. from list_capabilities) and need its full detail; to enumerate
all capabilities of a model, use list_capabilities instead. |
| get_functional_coverageA | Get the full functional coverage report for a model. Read-only; no side effects. Returns per-objective state (verified /
covered / failing / untested), the Capabilities × Conditions matrix, and
the applicable / missing-objective / not-applicable cell accounting. This
is the complete picture; when you only need the actionable subset (what to
implement or fix next), use check_functional_gaps instead. |
| check_functional_gapsA | Get the actionable functional gaps for a model. Read-only; no side effects. Returns the subset of the coverage report that
needs action: applicable conditions with no objective yet, and objectives
that are failing or have no passing test. Use this to decide what to
implement or fix next; for the complete coverage matrix and all states use
get_functional_coverage instead. |
| add_functional_testA | Hand-author a single functional test and map it to one or more objectives. Mutating. Generation (generate_functional_objectives) already specifies the tests to implement, so use this only to register an extra test that generation did not produce; a manually-added test survives regeneration/refresh. For bulk-registering tests that already exist in your codebase, use import_functional_tests instead. This records the test at the status you claim — it does not run or verify anything; CI verification happens only when you attach TEST_EXISTS/TEST_PASSES evidence via submit_functional_test_assertions. |
| import_functional_testsA | Register tests that already exist in your codebase against a model's functional objectives, so tests you already have count toward functional conformance — not only Mipiti-specified tests. Mutating (bulk). Scan the repo's test suite and pass the tests here. Optionally associate each with the objective ids it covers (from get_functional_objectives); the platform verifies each association is applicable before accepting it and returns any it rejected under rejected_mappings. A test with no (or a rejected) association is still imported, unmapped, so it can be associated later (see suggest_functional_test_mappings / associate_functional_test). For a single hand-authored test, use add_functional_test instead. |
| suggest_functional_test_mappingsA | Suggest which functional objectives each imported test likely covers. For unmapped tests (imported without an association, or added without
objective ids), this proposes objective mappings so you can review and
apply them with associate_functional_test. It only suggests — nothing is
associated until you confirm. |
| associate_functional_testA | Associate a functional test with one or more functional objectives. Use this after suggest_functional_test_mappings, or to hand-map a test to
the objectives it covers. The platform verifies each association is
applicable before accepting it and returns any it declined under
rejected_mappings. |
| get_functional_satisfaction_groupsA | Read the satisfaction-group structure for a functional objective. Read-only; no side effects. A satisfaction group is a set of functional tests that together satisfy the objective: AND within a group (every test in the group must be verified), OR across groups (any one complete group satisfies the objective). Returns the current numbered groups plus any tests associated with the objective but not placed in a group. Use before set_functional_satisfaction_groups to see the current structure, or to trace why an objective is / isn't satisfied. This is the functional analog of get_control_assumption_groups / get_mitigation_groups. |
| set_functional_satisfaction_groupsA | Declaratively set (replace) a functional objective's satisfaction groups. Mutating. Replaces the objective's group structure wholesale. Each group is a set of functional tests that together satisfy the objective (AND within a group); the objective counts as satisfied when any one complete group has all its tests verified (OR across groups). Tests you want to keep associated with the objective but outside any group go in ungrouped. Unlike set_control_assumption_groups, there is no AI relevance gate — the structure you submit is applied as-is. Read the current state first with get_functional_satisfaction_groups. |
| get_functional_test_sufficiencyA | Read the sufficiency verdict for a functional test. Read-only; no side effects. Reports whether the test's attached evidence adequately proves the objective(s) it is associated with, together with the reasoning behind the verdict. This is the functional-conformance analog of get_sufficiency (which covers security controls). The verdict is computed asynchronously after evidence is submitted, so it may read as pending or absent until evaluation completes. |
| get_cwe_catalogA | Get the platform's CWE reference catalog status. Returns {enabled, current_version, entry_count, versions}. When CWE
classification is not turned on for this instance, enabled is false
and the rest is empty — this is a normal informational response, not an
error. |
| get_model_cwe_tagsA | List CWE weakness classifications tagged onto a model's control objectives. Each tag's name/description are resolved from the platform's CWE catalog,
never model-authored. A tag whose CWE id has since been deprecated,
redefined, or removed by MITRE carries a stale reason (missing /
deprecated / changed) — re-run classify_model_cwe to refresh
it. 404s if CWE classification is not enabled on this instance. |
| classify_model_cweA | Classify a model's control objectives against the platform CWE catalog. Grounded: the model may only select from the catalog's current-version
candidate ids, and every returned id is re-validated against the catalog
before storage — a hallucinated or deprecated id is never persisted.
Skips control objectives already tagged at the catalog's current version
unless force is set. Returns a summary:
{status, catalog_version, cos, classified, tags_written, skipped}.
404s if CWE classification is not enabled on this instance. |
| get_entityA | Get a single entity of any core type by ID. Read-only. Dispatches on entity_type to the per-type read and returns that
type's native record as-is (not wrapped in an array): asset — the asset's typed fields. Soft-deleted assets carry
deleted: true; the caller decides whether to surface them.
entity_id e.g. A-01.
attacker — the attacker with its factor decomposition.
Soft-deleted attackers carry deleted: true. entity_id e.g.
T-03.
component — the component. Speculative components
(repo_url="") are returned as-is: the empty repo IS the
lifecycle state, not an error. entity_id e.g. CMP-01.
trust_boundary — the boundary incl. its passes set
(closed-vocabulary subset of
{Network, Adjacent, Local, Physical}). entity_id e.g.
TB-Net.
assumption — the assumption with its override applied (mirrors
list_assumptions' merge for one entity: typed fields, the
structured exclusion predicate when present, and the override
layer — status / justification / linked CO IDs / target model).
Soft-deleted assumptions carry deleted: true. entity_id
e.g. AS-01.
|
| remove_entityA | Soft-delete a single entity of any core type. Mutating: creates a
new model version. Reversible with restore_entity using the same
entity_type — the entity's ID is preserved (never reused) so a
restore reinstates the same ID and all its links. To change an
entity's fields instead of removing it, use the typed edit_* tool. Dispatches on entity_type. Per-type consequence (all derived at
read time; nothing is hard-destroyed): asset — the asset's (asset × attacker) CO pairs are tombstoned,
orphaning any controls mapped to them.
attacker — control objectives anchored to this attacker are
tombstoned; controls left with no live anchor become orphaned.
component — controls scoped to this component have their
component_id cleared (the controls themselves are kept) and the
component's trust-boundary contribution to asset reachability is
withdrawn.
trust_boundary — reachability widens: attacker vectors the
boundary was filtering now pass freely and its sealed/isolation
claim is dropped, so CO reachability verdicts past it can flip
toward reachable/indeterminate.
assumption — marked deleted (kept for the audit trail); linked
COs are no longer mitigated by it; controls with assumed_by
pointing to it are preserved as inert pointers that reconnect on
restore.
|
| restore_entityA | Un-soft-delete a single entity of any core type, reversing a prior
remove_entity. Mutating: creates a new model version. Only affects
an entity that is currently soft-deleted. Dispatches on entity_type. Per-type effect: asset — revives the asset's tombstoned (asset × attacker) COs
with their original IDs, un-orphaning any linked controls.
attacker — reinstates the attacker under its original ID,
revives the COs tombstoned when it was removed, and un-orphans any
controls that were anchored to it.
component — reinstates the component under its original ID,
restoring its trust-boundary contribution to asset reachability.
trust_boundary — reinstates the boundary: the reachability it
filtered re-narrows and its sealed/isolation claim is restored,
so CO reachability verdicts past it can flip back toward
unreachable.
assumption — returns the assumption to active status; controls
whose assumption_groups referenced it keep their group
structure intact. Re-attestation is required before it mitigates
COs again.
|
| get_risk_viewA | Prioritized Risk View — one row per live Control Objective — at a chosen scope. Read-only; no side effects. scope selects the aggregation boundary and how scope_id is interpreted:
"model" — a single threat model (scope_id = model id). One row per live CO with derived risk tier, asset impact, attacker likelihood, control coverage counts (coverage_ratio), and open-finding count (open_findings). Tombstoned COs are excluded; pair with get_threat_model if historical context is needed. Use to triage which COs need attention on one model — a single call ranks the work, no per-CO fan-out.
"system" — every model in a System, a group of related threat models (scope_id = system id). Same row shape as model with model_id and model_title added per row, so rows can be grouped/filtered by source model without an extra lookup. Use for posture queries spanning multiple models in the same product or service.
"tag" — every member model of a tag, a freely-composed cohort (scope_id = tag id). One delegation-aware row per CO across members (delegation_mitigated / delegating_controls): a CO mitigated via a verified cross-model delegation reads as covered, consistent with each model's own assessment. Use for a portfolio/audit-scope posture rollup.
|
| get_compliance_reportA | Compliance gap-analysis report for one framework at a chosen scope. Read-only; no side effects. System/tag scopes require PRO tier. Evaluates every framework requirement against the mapped controls in scope and classifies each as covered, partial, uncovered, unmapped, or excluded, then returns coverage counts plus per-requirement rows. The framework must first be activated at the same scope via select_compliance_frameworks (with the matching scope), otherwise there is nothing to report on. scope selects the boundary and how scope_id is read:
"model" — a single threat model (scope_id = model id).
"system" — rolled up across every model in a System, a group of related threat models (scope_id = system id).
"tag" — rolled up across every member model of a tag cohort, a freely-composed set of models (scope_id = tag id).
Filtering / pagination: level — level filter for level-aware frameworks; returns only requirements at or below this level (e.g. 1 for L1 only). Omit (or 0) for all levels. Honored for all scopes.
status — one of "covered", "partial", "uncovered", "unmapped", "excluded"; empty = all statuses. Model and system scopes only.
offset / limit — per-requirement row pagination; offset skips the first N rows, limit caps rows returned (0 = no explicit limit). Model and system scopes only.
A tag report is neither paginated nor status-filtered; passing status, offset, or limit with scope="tag" raises an error rather than silently returning unfiltered rows. |
| select_compliance_frameworksA | Select (activate) compliance frameworks at a chosen scope. Requires PRO tier. Mutating. Discover valid ids with list_compliance_frameworks (or add a custom one via import_compliance_framework); view the resulting gap analysis with get_compliance_report at the same scope. Re-calling replaces the scope's framework selection. scope selects the target and how scope_id is read:
"model" — a single threat model (scope_id = model id). Activating a framework also kicks off background auto-remediation: it auto-maps existing controls to requirements, excludes non-applicable requirements by taxonomy, and suggests/applies new entities for the remaining gaps. The response includes auto_remediate_jobs, which run and complete on their own; re-trigger later with auto_remediate_compliance if the model changes.
"system" — a System, i.e. a group of related threat models (scope_id = system id). Sets the system's active frameworks for portfolio-level compliance reporting.
"tag" — a tag cohort (scope_id = tag id). Records the frameworks against the tag AND propagates them to every member model, making the tag a compliance scope (e.g. an audit boundary) spanning several models.
|
| export_reportA | Export a threat model or a tag cohort as a downloadable document. Read-only; no side effects on the source. scope selects what is exported and how scope_id is read; format selects the representation:
scope="model" (scope_id = model id) supports format ∈ {csv, pdf, html, archive}:
csv — the model's current state rendered as CSV; returned inline as UTF-8 text in content.
pdf / html — rendered document returned base64-encoded in content_b64 (with content_type). Runs as a server-side job; progress is reported automatically while it completes, which may take time for large models.
archive — the self-contained, independently-verifiable JSON audit bundle: every version, controls, assertions (with Tier 1 / Tier 2 verdicts and attested flags), findings, risk acceptances, assumption overrides, attestations, and instance sufficiency signatures. Returned as {..., "envelope": <dict>}; feed the envelope to import_threat_model_archive to restore it into any workspace. Model scope only.
scope="tag" (scope_id = tag id) supports only format="html": the signed auditor report, aggregating every member model's report plus the cross-model dependency graph and attestation status into one HTML document, returned inline in content. csv, pdf, and archive are rejected for tag scope.
|
| list_groupsA | List the workspace's groups of a given kind. Read-only; no side effects. A "group" is a named collection of threat models. Two kinds, with distinct
semantics and DIFFERENT response shapes: kind values:
"tag": overlapping, semantics-free groupings — for audit scopes,
ad-hoc selections, or portfolios. A model may carry many tags, and a
tag never affects posture or credit. Returns {"tags": [...]}.
"system": named groupings of threat models for portfolio-level
risk and compliance reporting; unlike tags these drive system-scoped
risk/compliance rollups. Returns {"items": [<system>, ...]} where
each system carries id, name, description, model_count.
Discover group IDs here before the group risk/compliance/export tools or
before adding/removing members. For a single model's tag memberships use
list_model_groups. |
| create_groupA | Create a group (tag or system), optionally seeding tag members. Mutating. A "group" is a named collection of threat models. Group names are unique
per workspace within their kind. kind values:
"tag": an overlapping, semantics-free grouping — for viewing/
reporting without asserting any relationship between members and
without moving credit. Honors model_ids as an initial member seed.
Returns the created tag.
"system": a named grouping for portfolio-level risk and compliance
reporting. Systems are NOT seeded at creation — model_ids must be
omitted/empty for kind="system" (passing members raises); add them
afterward with add_model_to_group(kind="system", ...). Returns the
created system with its new ID.
|
| add_model_to_groupA | Add a threat model to a group as a member. Mutating. Links the model into the group without moving or copying it — the model
stays independently editable. Both the group and the model must already
exist. kind values:
"tag": add the model to a tag. Membership is overlapping — a model
may belong to many tags. Returns the updated tag payload.
"system": add the model to a system container for portfolio-level
risk and compliance reporting. Returns an ok result.
Note: member REMOVAL is tag-only (see remove_model_from_group); the
API has no remove-member endpoint for systems. |
| get_groupA | Get a system group by ID, including summaries of its member threat models. Read-only; no side effects. Single-group fetch is supported for SYSTEMS ONLY — tags have no
fetch-by-id endpoint; enumerate tags with list_groups(kind="tag") and
a single model's tag memberships with list_model_groups. A system is a
named grouping of threat models for portfolio-level risk and compliance
reporting. Discover system IDs with list_groups(kind="system"); add
members with add_model_to_group(kind="system", ...). |
| delete_groupA | Delete a tag group (the grouping only; member models are not affected). Deletion is supported for TAGS ONLY — systems have no delete endpoint on
this API. A tag is an overlapping, semantics-free grouping; removing it
leaves its member models untouched. |
| remove_model_from_groupA | Remove a model from a tag group (the model itself is not deleted). Member removal is supported for TAGS ONLY — systems have no remove-member
endpoint on this API (a model added to a system via
add_model_to_group(kind="system", ...) cannot be detached through
this client). Removing a model from a tag leaves the model untouched. |
| list_model_groupsA | List the groups a given model belongs to. Read-only; no side effects. Returns the model's TAG memberships (/api/models/{id}/tags) — tags are
the overlapping grouping kind, so a model may appear under many. There is
no per-model listing for systems; enumerate systems with
list_groups(kind="system") and inspect membership via each system's
get_group. Use list_groups(kind="tag") for all tags in the
workspace. |
| link_system_dependencyA | Link an external assumption to a target model in the same system. Makes the assumption a cross-model (system-scoped) dependency: it becomes a
compliance requirement on the target model. Two independent satisfaction
paths: auto-attestation when the target model's controls satisfy the
requirement (no manual action needed), or manual attestation via
submit_attestation. Either path alone suffices. The assumption must already be linked to control objectives (via
add_assumption or edit_assumption with linked_co_ids). Pass empty
target_model_id to unlink. Inspect the resulting dependency graph with
get_system_dependencies. |
| get_reachability_verdictsA | Per-CO reachability verdicts for a model — flat or composed topology. composed selects which topology the verdicts are derived over:
composed=False (default) — FLAT: verdicts over THIS model's own
structural primitives only (components, asset.component_ids,
trust_boundary.passes, attacker.trust_boundary_ids + attack_vector,
Assumption.exclusion predicates). Pure derivation, NOT persisted on
the CO — re-running against the model JSON is deterministic, the
verification an auditor performs. Pass co_id to retrieve a
single verdict (skips the cross-CO loop); page / page_size /
kind_filter are ignored in this mode. Returns {model_id, model_version, verdicts: [...]} where each verdict carries
co_id, kind ("reachable" | "unreachable" |
"indeterminate"), reason (structural label:
boundary_blocks_vector / assumption_excludes /
attacker_unpositioned / asset_unbounded /
no_shared_boundary / missing_entity), narration, and
(when applicable) boundary_id / assumption_id.
composed=True — COMPOSED: the same verdict semantics evaluated
over the merged effective tree (own components and trust boundaries
combined with everything inherited from ancestors, qualified ids for
cross-model references). Use this when the model is a child on the
composition tree and you need reach state that reflects the ancestor
topology, not just the local model document. Paginated via page
/ page_size and filterable via kind_filter; co_id is
ignored (the composed surface has no single-CO lookup). Returns
{model_id, flag_enabled, verdicts: [{co_qid, asset_qid, attacker_qid, kind, reason}, ...], total, page, page_size}. When
composition is disabled on the backend, verdicts is empty and
flag_enabled: false — fall back to composed=False for the
per-model derivation.
When a flat verdict is indeterminate, address the gap via the standard
model-edit affordances: attacker_unpositioned → edit_attacker setting
trust_boundary_ids
asset_unbounded → assign_to_components (target_type="asset") or
edit_asset with component_ids
no_shared_boundary → re-position attacker, re-scope asset, OR
add_assumption with structured exclusion
missing_entity → restore the missing asset/attacker, or remove
the orphaned CO
Use this before relying on per-CO reach state for triage,
auto-remediation, or audit responses. The model_coherence_report
tool surfaces the same gaps as actionable findings; this tool exposes
the raw verdicts when you need the structured data (boundary_id
citations, narration strings) that the findings summarize. |
| recompute_verdictsA | Re-run coverage and group-sufficiency verdict evaluation for a model,
or return the pre-flight cost estimate without enqueueing anything. dry_run selects between enqueueing the recompute and a cost-only
quote:
dry_run=False (default) — ENQUEUE: force a fresh evaluation of
every control's coverage verdict and every live control objective's
group-sufficiency verdict, bypassing the normal quiet-period
batching. Evaluation runs in the background; re-read the model's
divergence report (or coverage surfaces) shortly after to see
updated verdicts. The response carries estimated_credits — an
informational estimate; nothing is charged from it, actual usage is
metered as the evaluation runs, per the account's plan. Returns
{model_id, model_version, enqueued_coverage, enqueued_group_sufficiency, total_enqueued, estimated_credits, quote, governor}. When governor.exhausted is true the work is
queued and resumes automatically at governor.resets_at — it is
never dropped.
dry_run=True — QUOTE ONLY: return the informational pre-flight
cost estimate and enqueue NOTHING. Nothing is charged from the
estimate. It carries computed_at and the pricing rate_version
in force so a stale quote is detectable. Returns
{estimated_credits, computed_at, rate_version, informational, total_enqueueable, already_evaluated, governor}, where
total_enqueueable is the number of jobs a recompute would enqueue
and already_evaluated counts subjects that already carry a
verdict (a portion short-circuit without cost, so the estimate is an
upper bound). When governor.exhausted is true, new evaluation
would be queued until governor.resets_at.
Both modes return a 503-mapped error when verdict observability is
unavailable on the deployment. To un-park verdicts stuck by a transient
outage instead of force-enqueueing the whole model, use
retry_verdicts. |
| list_reconciliation_candidatesA | Reconciliation triage surface between this model and its ancestors. When a model inherits entities (assets, attackers, components, trust
boundaries) from an ancestor and the operator has authored a
locally-named entity that looks like the same real-world thing, the
reconciliation engine pairs them so the operator can decide whether to
alias the local entity onto the inherited qualified id. disposition
selects which side of the triage queue to read: disposition="active" (default) — the OPEN candidate queue:
detected pairs the operator has not yet acted on. Tier certain
is a deterministic match (same qid or structurally identical) and is
safe to auto-apply via apply_certain_reconciliation_match; tier
heuristic is a fuzzy name/description match that needs review.
Previously-rejected pairs are filtered out of this queue. Paginated
via page / page_size. Returns {model_id, flag_enabled, total, tiers: {certain: int, heuristic: int}, page, page_size, candidates: [{kind, own_qid, inherited_qid, tier: "certain"|"heuristic", reasons: [str, ...]}, ...]}. When
composition is disabled on the backend, total is 0,
candidates is empty, and flag_enabled: false.
disposition="rejected" — the operator's persisted "these are NOT
duplicates" decisions, in rejected_at ascending order (the same
set the candidate detector consults to filter the active queue). Use
this to render the rejected section of a triage view, or to find the
surrogate id needed by unreject_reconciliation_candidate.
NOT paginated — page / page_size are ignored. Returns
{model_id, flag_enabled, rejections: [{id, model_id, kind, own_qid, inherited_qid, rejected_by, rejected_at}, ...]}. When
composition is disabled on the backend, rejections is empty and
flag_enabled: false; the same empty list is returned with
flag_enabled: true when the rejection store is not configured on
the instance.
Use on child models in a recursive tree to find duplicates that should
be collapsed before they distort coverage. |
| preview_undo_compositionA | Preview the inverse plan (or divergence refusal) for a prior
composition event WITHOUT mutating any state. Read-only. Read-only counterpart to undo_composition_event. Used by the
confirmation flow so the operator sees what an undo would do before
committing — either the inverse state operations the apply step will
commit, or the enumerated reasons the divergence detector refuses the
undo. Same {plan, refusal} return shape for both event types. |
| undo_composition_eventA | Apply the inverse of a previous composition event. Mutating —
persists inverse state across multiple models. Re-runs the divergence detector immediately before applying and
refuses with 409 + the structured refusal block when state has
materially evolved since the forward event (assertions submitted on
the affected entity, downstream COs added that reference it, the
entity edited, etc.). On success, persists the inverse state
operations across every affected model and emits a structured
lift_undone / split_undone activity event citing
original_event_id so the audit pack can chain undo to its forward. |
| get_functional_objectivesA | List a model's functional objectives, or fetch one by id. Read-only; no side effects. A functional objective is a Capability × Condition test plan expressed as a
Given-When-Then statement. functional_objective_id selects the behaviour: omitted / empty string -> list every functional objective for the model
(the full functional test plan). a functional-objective id -> return just that one objective's detail,
including its capability, condition, Given-When-Then statement, and
current test state.
For pass/fail coverage state across all objectives use
get_functional_coverage; for the actionable gaps use
check_functional_gaps. |
| submit_functional_test_assertionsA | Attach machine-verifiable evidence assertions to one already-existing functional test so CI can verify it. Mutating. This submits EVIDENCE for a test that already exists (identified by
functional_test_id) — it does not create or register the test. It is the
functional-conformance analog of submit_assertions (which covers security
controls): it binds assertions such as "the test exists" and "the test
passes" to the functional test, and an independent CI run against the named
repo is what turns an operator's "verified" claim into verified state. To bulk-register test DEFINITIONS from your codebase instead, use
import_functional_tests; to hand-author a single test use
add_functional_test. Call this after the test is implemented (e.g. following
get_scan_prompt (kind="functional")), then read the resulting state via
get_functional_coverage or get_functional_test_sufficiency. |
| get_controlsA | Get implementation controls for a threat model — list or single-control detail. Read-only (with one list-mode side effect, below). Two modes, selected by whether control_id is set: List mode (control_id omitted) — returns the controls that
should be implemented to satisfy the model's control objectives, as
{"controls": [...], "total": N, "returned": M}. One side effect:
if controls have never been generated for this model, the first
call triggers generation. Generation may finish inline or continue
in the background — if results look incomplete, poll
get_control_generation_status and re-read once it reports
complete. The filters (status, co_id, component_id),
pagination (offset/limit), and the include_deleted /
include_orphaned / summary_only toggles apply only in this
mode. By default list mode excludes ORPHANED controls (controls
whose every mapped CO is tombstoned because its asset/attacker pair
was removed in a later version); pass include_orphaned=True to
include them — each returned control carries a boolean orphaned
field so callers can render the distinction. Detail mode (control_id set) — returns a single control
directly (NOT wrapped in an array) with verified-status enrichment
and an orphaned flag derived from the live CO set. 404 if the
control doesn't exist on the requested version. Pass version to
read the control as of a specific model version. The list-mode
filters, pagination, and toggles are ignored in this mode.
|
| get_control_objectivesA | Get the control objective matrix, or one control objective. Read-only. Two modes, selected by whether co_id is set: Matrix mode (co_id omitted) — returns the model's COs, each
with references to the controls that cover it. By default returns a
compact summary (total count only); pass offset/limit to
page through full CO records. Single mode (co_id set) — returns that one CO's typed
fields, the IDs of any controls that map to it, and the
deterministic reachability verdict (the structural derivation that
backs any reach claim on the CO). Tombstoned COs (removed: true) are returned with the flag set; the verdict is omitted
because reach state is frozen at the removal version.
offset/limit are ignored in this mode.
For pass/fail assurance scoring use assess_model. |
| assign_to_componentsA | Replace an asset's or a control's component scope. Mutating. Components are the canonical bridge between security architecture
(trust boundaries) and code organization (repos). target_type
selects what is being scoped: "control" — replace a control's component scope. A control
scoped to one or more components is visible to coding agents
working in those repos (matched via Component.repo_url +
Component.path); an unscoped control is visible everywhere. Use
when wiring a previously unscoped control to the component(s) that
implement it, adding a second component to a cross-cutting control
(e.g. "all microservices enforce JWT validation"), or correcting a
wrong assignment. target_id is the control ID (e.g. "CTRL-03").
"asset" — replace an asset's component scope. Linking assets to
components flows boundary context into reachability derivation
without giving Asset its own trust_boundary_ids. Multi-component
is the right shape for a multi-instance asset (e.g., a session
token on client + cache + DB — each component handles a distinct
instance). target_id is the asset ID (e.g. "A1").
Both variants are mechanical / non-AI-gated and validate only that
every referenced component exists on the model. |
| get_scan_promptA | Get guidance prompts for scanning a codebase. Read-only; no side effects. kind selects which scan brief to return:
"security" (default) — prompts telling the agent what evidence
to look for per security control; only NOT_IMPLEMENTED controls are
included (implemented ones need no scan). Use this to drive a
gap-discovery pass, then record what is missing with
submit_findings and what is present with submit_assertions.
Pass control_id to scope the prompt to one control; empty
(default) returns prompts for all not-yet-implemented controls.
"functional" — the agent brief for implementing
functional-conformance tests. Generation specifies the functional
tests, so for each test not yet verified this returns its
implementation brief and the objectives it proves; it also reports
objectives_without_tests (regenerate or add a test) and
missing_objectives (applicable conditions with no objective
yet). Drive test implementation from it, then call
submit_functional_test_assertions with TEST_EXISTS + TEST_PASSES
assertions so CI verifies each test; read the resulting pass/fail
state via get_functional_coverage. control_id does not
apply to this kind and is ignored.
|
| set_control_objective_calA | Set the per-CO ISO/SAE 21434 Cybersecurity Assurance Level (CAL). CAL is a 1-4 grade on each individual control objective that
expresses how much assurance the control program owes for that
specific objective. It lives on the control_objectives identity
side-table — writes do NOT create a new threat-model version, and
the value survives soft-delete + revival of the CO. Pass cal=None (or omit it) to clear the value. |
| revalidate_entity_qualityA | Re-run quality validation on a threat model's existing assets and
attackers, as if they were freshly generated. A fast first-pass check
judges every entity; only the ones it flags get a deeper review that
confirms them, sharpens their wording, or flags them for you. Use this to apply validation improvements to an already-generated model, or
to clear stale quality warnings — without regenerating the whole model
(which would destroy controls, assertions, and components). It is
non-destructive: an entity that should be removed is left in place with a
quality warning rather than deleted, so no control objective loses its asset
or attacker anchor. The result is saved as a new model version; controls and
control objectives carry forward. May consume credits for the entities that need the deeper review; a model
already in good shape costs nothing. Returns the updated model envelope:
{"accepted": true, "model": {...}}. |
| auto_remediate_complianceA | Automatically close compliance gaps for a framework. Requires PRO tier. Three-phase loop: (1) auto-map existing controls to unmapped requirements,
(2) exclude requirements for non-applicable taxonomy primitives,
(3) suggest and apply new assets/attackers for remaining gaps. Phase (3) routes every proposal whose name matches a soft-deleted
asset/attacker through the same restore-candidate LLM gate
add_asset uses, so reanimating a previously removed entity
reinstates its stable ID and every CO tombstone + control tied to
it (rather than spawning a duplicate fresh ID). The response
distinguishes assets_added / attackers_added (genuinely new)
from assets_restored / attackers_restored (revived soft-
deletes) and lists restored_asset_ids / restored_attacker_ids.
Proposals the gate classified as similar (or that fail-closed
on an unavailable / malformed gate response) appear under
skipped with a per-entry reason — the operator decides whether
to restore manually or rephrase. Converges automatically: stops when fully covered or when no further
progress can be made. This runs automatically when a framework is selected, but can be
re-triggered manually if the model changes. |