Python API Reference¶
Top-level exports¶
notarize
¶
notarize - Canonical trace format and verifier for agent execution attestation
ClosedLoopError
¶
Bases: ValueError
Raised when the gate refuses empty or unusable traces.
GateOutcome(ok, verdict, reason, exit_code, verification=None, trace_id=None, failed_step_indices=(), degraded_step_indices=(), silent_success=False)
dataclass
¶
Result of a closed-loop read of a notarize trace.
Attributes:
| Name | Type | Description |
|---|---|---|
ok |
bool
|
True only when verification would let a pipeline continue. |
verdict |
str
|
|
reason |
str
|
Human-readable explanation (always non-empty). |
exit_code |
int
|
0 for PASS, 1 for FAIL (tamper/invalid/degraded), 2 for FAIL_LOUD. |
verification |
VerificationResult | None
|
Underlying :class: |
trace_id |
str | None
|
Trace identifier when available. |
failed_step_indices |
tuple[int, ...]
|
Steps with hard-failure results. |
degraded_step_indices |
tuple[int, ...]
|
Steps with degraded/partial results. |
silent_success |
bool
|
True when claimed success conflicts with step outcomes. |
to_dict()
¶
Serialise for JSON reports (eagle-eyes dogfood, CI artifacts).
Source code in src/notarize/closed_loop.py
PrivacyScrubber
¶
Structure-preserving PII redaction for agent traces.
Scrubs the following PII patterns from step action, observation, and result fields: - Email addresses → [EMAIL_REDACTED] - Phone numbers → [PHONE_REDACTED] - Credit card numbers → [CREDIT_CARD_REDACTED] - Social Security Numbers → [SSN_REDACTED] - IP addresses → [IP_REDACTED]
scrub(trace)
¶
Scrub PII from a trace's step fields.
Deep-copies the trace before modification to preserve the original.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trace
|
AgentTrace
|
The AgentTrace to scrub. |
required |
Returns:
| Type | Description |
|---|---|
ScrubResult
|
A ScrubResult containing the scrubbed trace and replacement statistics. |
Source code in src/notarize/scrubber.py
ScrubResult(original_trace_id, scrubbed_trace, replacements_count, patterns_matched)
dataclass
¶
Result of scrubbing PII from a trace.
Attributes:
| Name | Type | Description |
|---|---|---|
original_trace_id |
str
|
The trace_id of the original (pre-scrub) trace. |
scrubbed_trace |
AgentTrace
|
A deep-copied AgentTrace with PII replaced. |
replacements_count |
int
|
Total number of replacements made. |
patterns_matched |
list[str]
|
List of pattern names that were triggered. |
to_dict()
¶
Serialize to a JSON-compatible dict.
Source code in src/notarize/scrubber.py
TraceStore(path)
¶
SQLite-backed store for traces and verification results.
All traces and results are stored in a single SQLite database. Deduplication is by trace_id for traces and by id for results.
Attributes:
| Name | Type | Description |
|---|---|---|
path |
Path to the SQLite database file. |
Source code in src/notarize/store.py
close()
¶
save_trace(trace)
¶
Store an AgentTrace (upsert by trace_id).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trace
|
AgentTrace
|
The AgentTrace to save. |
required |
Source code in src/notarize/store.py
get_trace(trace_id)
¶
Retrieve an AgentTrace by trace_id, or None if not found.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trace_id
|
str
|
The user-provided trace identifier. |
required |
Returns:
| Type | Description |
|---|---|
AgentTrace | None
|
The AgentTrace, or None. |
Source code in src/notarize/store.py
list_traces()
¶
Return all stored AgentTrace objects ordered by created_at.
Returns:
| Type | Description |
|---|---|
list[AgentTrace]
|
List of AgentTrace objects, oldest first. |
Source code in src/notarize/store.py
save_result(result)
¶
Store a VerificationResult (upsert by id).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
result
|
VerificationResult
|
The VerificationResult to save. |
required |
Source code in src/notarize/store.py
get_result(result_id)
¶
Retrieve a VerificationResult by id, or None if not found.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
result_id
|
str
|
The content-addressed result ID. |
required |
Returns:
| Type | Description |
|---|---|
VerificationResult | None
|
The VerificationResult, or None. |
Source code in src/notarize/store.py
list_results()
¶
Return all stored VerificationResult objects ordered by timestamp.
Returns:
| Type | Description |
|---|---|
list[VerificationResult]
|
List of VerificationResult objects, oldest first. |
Source code in src/notarize/store.py
AgentTrace(trace_id, agent_name, task, steps, created_at=time.time())
dataclass
¶
A hash-chained sequence of TraceSteps with a Merkle root.
The steps form a linked chain where each step's parent_id points to the previous step's id. A Merkle root is computed from all step IDs to enable tamper detection.
Attributes:
| Name | Type | Description |
|---|---|---|
trace_id |
str
|
User-provided trace identifier. |
agent_name |
str
|
Name of the agent that produced this trace. |
task |
str
|
What the agent was asked to do. |
steps |
list[TraceStep]
|
Ordered list of TraceStep objects. |
merkle_root |
str
|
SHA-256[:16] of the sorted step IDs. |
created_at |
float
|
Unix timestamp when this trace was created. |
id |
str
|
SHA-256[:16] of "trace_id|agent_name|task|merkle_root". |
to_dict()
¶
Serialize to a JSON-compatible dict.
Source code in src/notarize/trace.py
from_dict(d)
classmethod
¶
Deserialize from a dict produced by to_dict().
Source code in src/notarize/trace.py
TraceStep(step_index, action, observation, result, tool_name='', timestamp=time.time(), parent_id=None)
dataclass
¶
A single step in an agent execution trace.
Steps are content-addressed by their step_index, action, observation, and result. Each step points to the previous step's ID via parent_id, forming a hash chain.
Attributes:
| Name | Type | Description |
|---|---|---|
step_index |
int
|
Zero-based index of this step in the trace. |
action |
str
|
What the agent did (e.g. "tool_call:search"). |
observation |
str
|
What the agent observed. |
result |
str
|
What happened (e.g. "success", "error"). |
tool_name |
str
|
Optional tool name used in this step. |
timestamp |
float
|
Unix timestamp of this step. |
id |
str
|
SHA-256[:16] of "step_index|action|observation|result". |
parent_id |
str | None
|
The previous step's ID, or None for the first step. |
to_dict()
¶
Serialize to a JSON-compatible dict.
Source code in src/notarize/trace.py
from_dict(d)
classmethod
¶
Deserialize from a dict produced by to_dict().
Source code in src/notarize/trace.py
CompiledWorkflow(step_ids, edges, hard_edge_count, suspected_edge_count, residual_llm_count, retry_noise_count, exploration_noise_count)
dataclass
¶
Mostly deterministic workflow compiled from noisy traces.
ToolInvocation(step_id, tool, arguments=dict(), outputs=dict(), is_retry=False, is_exploration=False)
dataclass
¶
One tool step in a noisy agent trace (pre-compile).
WorkflowEdge(producer_step, consumer_step, producer_key, consumer_arg, binding, strength, evidence=(), value_fingerprint='')
dataclass
¶
Producer→consumer dependency with optional evidence (TraceCompiler).
ConsistencyVerifier
¶
Verifies the internal consistency of an AgentTrace.
Performs the following checks:
1. Hash chain integrity: each step's id is recomputed from its content fields
(step_index, action, observation, result) and compared to the stored id;
also each step.parent_id == previous step.id. If either fails,
hash_chain_integrity is failed and tamper_detected is added.
2. Merkle root matches recomputed value
3. Step indices are monotonically increasing from 0
4. No duplicate step IDs
5. Trace ID matches stored trace.id
verify(trace)
¶
Verify the internal consistency of an AgentTrace.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trace
|
AgentTrace
|
The AgentTrace to verify. |
required |
Returns:
| Type | Description |
|---|---|
VerificationResult
|
A VerificationResult with verdict and check details. |
Source code in src/notarize/verifier.py
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | |
VerificationResult(trace_id, verdict, checks_passed, checks_failed, error, timestamp)
dataclass
¶
Result of verifying an AgentTrace.
Attributes:
| Name | Type | Description |
|---|---|---|
trace_id |
str
|
The trace_id of the verified trace. |
verdict |
str
|
One of "verified", "consistent", "tampered", "invalid". |
checks_passed |
list[str]
|
List of check names that passed. |
checks_failed |
list[str]
|
List of check names that failed. |
error |
str | None
|
Optional error message if an exception occurred. |
timestamp |
float
|
Unix timestamp of the verification. |
id |
str
|
Content-addressed identifier of this result. |
to_dict()
¶
Serialize to a JSON-compatible dict.
Source code in src/notarize/verifier.py
from_dict(d)
classmethod
¶
Deserialize from a dict produced by to_dict().
Source code in src/notarize/verifier.py
summarize(trace)
¶
Produce an AuditSummary for a single AgentTrace.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trace
|
AgentTrace
|
The AgentTrace to analyse. |
required |
Returns:
| Type | Description |
|---|---|
AuditSummary
|
An AuditSummary with risk flags and compliance score. |
Source code in src/notarize/audit.py
summarize_session(store, session_id)
¶
Return AuditSummary objects for all traces belonging to a session.
A trace belongs to the session if its trace_id starts with session_id OR its agent_name equals session_id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
store
|
TraceStore
|
The TraceStore to query. |
required |
session_id
|
str
|
A session prefix or agent name to match. |
required |
Returns:
| Type | Description |
|---|---|
list[AuditSummary]
|
A list of AuditSummary objects, one per matching trace. |
Source code in src/notarize/audit.py
assert_no_silent_success(claimed_ok, claimed_exit_code, trace, **kwargs)
¶
Raise :class:ClosedLoopError on SILENT-SUCCESS or other gate failure.
Source code in src/notarize/closed_loop.py
assert_trace_verified(trace, **kwargs)
¶
Gate a trace and raise :class:ClosedLoopError unless outcome is ok.
Source code in src/notarize/closed_loop.py
gate_claimed_success(claimed_ok, claimed_exit_code, trace, *, verifier=None)
¶
Gate a process claim (exit code / success flag) against the real trace.
SILENT-SUCCESS control for assemble-style pipelines:
claimed_ok=Trueorclaimed_exit_code==0with failed/degraded steps → FAIL (exit 1), never silent pass.- Claim already failed → still verify empty/tamper (may be FAIL_LOUD).
- Clean claim + clean trace → PASS.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
claimed_ok
|
bool
|
What the process reported ( |
required |
claimed_exit_code
|
int
|
Process exit code (0 = success claim). |
required |
trace
|
AgentTrace | str | Path
|
Execution trace to read. |
required |
verifier
|
ConsistencyVerifier | None
|
Optional consistency verifier. |
None
|
Source code in src/notarize/closed_loop.py
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | |
gate_trace(trace, *, verifier=None, refuse_degraded=True, refuse_failed_steps=True)
¶
Read one trace, verify hash-chain integrity, fail loudly on empty/wrong.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trace
|
AgentTrace | str | Path
|
:class: |
required |
verifier
|
ConsistencyVerifier | None
|
Optional verifier instance (defaults to a new one). |
None
|
refuse_degraded
|
bool
|
If True (default), degraded/partial steps → FAIL (SILENT-SUCCESS class - clean chain must not hide soft failure). |
True
|
refuse_failed_steps
|
bool
|
If True (default), any hard-failure step → FAIL even when the chain hashes correctly. |
True
|
Returns:
| Type | Description |
|---|---|
GateOutcome
|
class: |
Source code in src/notarize/closed_loop.py
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | |
step_is_degraded(step)
¶
True when the step is partial/degraded (not a clean success).
Source code in src/notarize/closed_loop.py
step_is_failed(step)
¶
True when the step records a hard failure result.
Source code in src/notarize/closed_loop.py
compare_traces(baseline, candidate)
¶
Compare two AgentTraces step by step.
For each step position both traces have in common, compute the similarity between the concatenated "action|observation|result" strings. Steps only present in one trace are marked "added" or "removed" with similarity 0.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
baseline
|
AgentTrace
|
The reference AgentTrace. |
required |
candidate
|
AgentTrace
|
The AgentTrace to compare against the baseline. |
required |
Returns:
| Type | Description |
|---|---|
TraceComparison
|
A TraceComparison with per-step breakdowns and an overall verdict. |
Source code in src/notarize/compare.py
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | |
to_compliance_report(trace, standard='SOC2')
¶
Generate a formal compliance report in markdown.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trace
|
AgentTrace
|
The AgentTrace to report on. |
required |
standard
|
str
|
One of 'SOC2', 'HIPAA', 'GDPR'. |
'SOC2'
|
Returns:
| Type | Description |
|---|---|
str
|
A markdown-formatted compliance report string. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If an unknown standard is specified. |
Source code in src/notarize/timeline.py
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | |
to_csv(trace)
¶
Export trace as CSV: step_index,action,input_summary,output_summary,duration_ms,timestamp
Source code in src/notarize/timeline.py
to_timeline_json(trace)
¶
Export as JSON array suitable for timeline visualizations.
Source code in src/notarize/timeline.py
assert_compiled_workflow_ok(workflow=None, **kwargs)
¶
Raise :class:ClosedLoopError unless :func:gate_compiled_workflow is ok.
Source code in src/notarize/trace_compile.py
compile_trace_workflow(invocations, *, drop_retries=True, drop_exploration=True)
¶
Mine producer→consumer edges from tool invocations (deterministic).
Hard edge rule (TraceCompiler): Admit a hard edge only when a consumer argument value is uniquely attributable to exactly one earlier producer's output value. Evidence tuple = (producer_step, producer_key, consumer_arg, fingerprint).
Ambiguous (value appears in 0 or ≥2 producers) → suspected edge with empty/weak evidence and no hard ordering obligation.
Argument values that match no producer
- empty / None → constant (if literal-looking) or user_input
- otherwise → llm_residual suspected edge from previous step (weak)
Source code in src/notarize/trace_compile.py
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 | |
gate_compiled_workflow(workflow=None, *, invocations=None, require_workflow=True, require_hard_edges=False, min_hard_edges=0, refuse_hard_without_evidence=True, refuse_all_llm_residual=True, max_residual_ratio=1.0)
¶
Refuse unattested or purely residual compiled workflows (TRACE-COMPILE).
Rules:
- No workflow when required → FAIL_LOUD
- Hard edge without evidence → FAIL_LOUD (audit break)
require_hard_edgesand hard_edge_count < min → FAIL- All bindings residual LLM when refuse_all_llm_residual and edges exist → FAIL
- residual ratio > max_residual_ratio → FAIL
- Suspected edges alone do not fail ordering (TraceCompiler)
- Clean hard edges with evidence → PASS
Source code in src/notarize/trace_compile.py
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 | |
hard_edges_missing_evidence(edges)
¶
Hard edges must carry non-empty evidence tuples.