EngineeringUnified Decision Logic: Introducing MODIFY and DEFER in Thoth SDK 0.1.16Read the post →
← Blog·Engineering

Unified Decision Logic: Introducing MODIFY and DEFER in Thoth SDK 0.1.16

The 0.1.16 release line ships MODIFY and DEFER decision types, canonicalizes observe mode, and surfaces the full ML decision envelope including feature vectors and score components in all three SDK languages.

Nyah Check

Nyah Check

May 15, 2026 · 7 min read

Minimalist technical diagram of Thoth SDK 0.1.x, showing unified MODIFY and DEFER decision outcomes across Python, Go, and TypeScript

Today we're shipping atensec-thoth 0.1.16 (Python), thoth-go 0.1.17 (Go), and @atensec/thoth 0.1.18 (TypeScript). Three SDK languages, same decision envelope the full set of fields the enforcer returns when it evaluates an agent tool call.

This is also the first release to include MODIFY and DEFER as first-class decision outcomes, and the first to surface the full ML decision envelope including feature vectors and score components directly in the SDK error types you catch.


Two new decision outcomes: MODIFY and DEFER

MODIFY means the enforcer rewrites tool arguments before the tool executes. The call goes through; the arguments meet policy before they land.

The healthcare case makes it concrete: an agent calls query_patient_records with an unbounded date range. The enforcer rewrites the range to the minimum-necessary window for the declared session intent, then allows the call. The agent sees the modified result; the audit trail shows both the original request and what changed.

In Python:

@thoth.wrap_tool
def query_patient_records(patient_id: str, date_range: str) -> dict:
    ...

# If the enforcer returns MODIFY, the decorated function is called
# with decision.modified_tool_args substituted for the original arguments.
# ThothPolicyViolation is NOT raised execution proceeds with patched args.

In Go, WrapToolFunc merges decision.ModifiedToolArgs into the call before dispatch. In TypeScript, instrument() does the same via decision.modifiedToolArgs.

DEFER tells the agent to retry later. It's different from STEP_UP: step-up waits for a human to approve inline; defer tells the caller to back off and try again after defer_timeout_seconds. Use it when a rate limit or data embargo is time-bounded a BLOCK is permanent, a DEFER is not.

Both decisions normalize legacy enforcer aliases: TRANSFORMMODIFY, HOLD/DEFERREDDEFER, DENYBLOCK. Callers see consistent enum values regardless of enforcer version.


Canonical observe mode

shadow mode is gone from the public SDK surface. The canonical value is now observe.

In observe mode, every tool call executes nothing is blocked. The enforcer evaluates policy and records what would have happened in the audit trail. Instrument, observe for seven days, review the shadow violations report, then decide which policies to promote to enforcement.

Callers who hardcoded "shadow" don't need to update running deployments immediately. The enforcer still accepts it and normalizes to observe at parse time. The SDK enum and documentation no longer use it.


The full decision envelope

When the enforcer blocks or step-up-challenges a tool call, it returns a rich decision record. Until this release, only a subset was surfaced in the SDK error type.

Six new fields are now in PolicyViolationError (Go) and ThothPolicyViolation (Python and TypeScript):

FieldWhat it carries
decision_envelope_versionSchema version of the enforcer response
enforcement_trace_idCorrelation ID that follows the request through the full enforcement pipeline
fastml_featuresFeature vector from the ML scoring tier
score_componentsComposite risk score broken down by component
top_contributorsHighest-weight features that drove the decision, ranked
decision_evidenceRaw evidence fields from the enforcer response envelope

A note on why fastml_features and score_components are grouped here.

Thoth's enforcement path runs through multiple analysis tiers. The ML scoring tier evaluates tool call risk in real time and produces fastml_features and score_components. When a call is flagged, a deeper analysis stage runs a comprehensive policy evaluation and produces decision_evidence and the regulatory references.

Most tool calls pass with a low score without triggering further analysis. When one is flagged, the full decision including the ML signals that triggered escalation is now in the SDK error you catch. No additional API calls needed to build an incident report.

top_contributors is the field security engineers will reach for first. It tells you which signals drove a block. If the same feature category consistently ranks highest for a specific agent, that's a tuning signal the agent's approved scope or behavioral profile may need adjustment. No log diving required.

enforcement_trace_id is what compliance teams need. It correlates a single tool call through every tier of the enforcement system. When an auditor asks what happened during a specific agent session, that ID follows the request across every system that touched it without cross-referencing separate log sources.


Upgrade path

Python:

pip install --upgrade "atensec-thoth>=0.1.16"

Go:

go get github.com/atensecurity/thoth-go@v0.1.17

TypeScript/Node:

npm install @atensec/thoth@0.1.18
# or
pnpm add @atensec/thoth@0.1.18

You don't need config changes. MODIFY and DEFER are handled automatically by the enforcement wrappers. To act on them explicitly:

Python:

from atensec_thoth import ThothPolicyViolation, DecisionType

try:
    result = my_governed_tool(args)
except ThothPolicyViolation as e:
    if e.decision == DecisionType.DEFER:
        # retry after e.defer_timeout_seconds
        time.sleep(e.defer_timeout_seconds or 30)
        result = my_governed_tool(args)

TypeScript:

import { ThothPolicyViolation, DecisionType } from "@atensec/thoth";

try {
  const result = await myGovernedTool(args);
} catch (e) {
  if (e instanceof ThothPolicyViolation && e.deferTimeoutSeconds) {
    await sleep(e.deferTimeoutSeconds * 1000);
    const result = await myGovernedTool(args);
  }
}

What's next

  • Updated HIPAA minimum-necessary pack with session scope enforcement; SOC 2 CC6 and FINRA 4370 packs.
  • The Day-7 shadow violations report, automated and delivered to your email without a call.
  • WebSocket endpoint for real-time governed event feeds, replacing the current polling model.

If you're on a design-partner pilot and have questions about upgrading, reach out in your shared Slack channel or at support@atensecurity.com.


Get practical updates on AI agent security and governance.

Twice monthly notes on incidents, controls, and implementation lessons from real enterprise deployments.