cd /news/ai-agents/sp-1-0-deterministic-reproducible-ve… Β· home β€Ί topics β€Ί ai-agents β€Ί article
[ARTICLE Β· art-74480] src=github.com β†— pub= topic=ai-agents verified=true sentiment=Β· neutral

SP/1.0: deterministic, reproducible verdicts for AI-agent decisions

Sovereign Logic released SP/1.0, the first open-source runtime circuit breaker for AI agents, on June 25, 2026. The protocol provides deterministic, cryptographically audited verdicts on tool execution, addressing documented production failures such as agent infinite loops that consumed $6,000+ in API costs. SHACKLE operates as a sidecar daemon or in-process library, enforcing 9 mathematical invariants and Ed25519-signed append-only audit logs.

read16 min views1 publishedJul 26, 2026
SP/1.0: deterministic, reproducible verdicts for AI-agent decisions
Image: source

Version: 1.0.0

Status: Published

Date: 2026-06-25

Authors: Dante Bullock, Sovereign Logic

License: Creative Commons Attribution 4.0 International (CC-BY 4.0)

Reference Implementation: https://github.com/Fame510/SHACKLE

First Public Commit: 2026-06-17 23:12 UTC

Implementations of this specification are subject to the SHACKLE license terms.The reference implementation is dual-licensed: AGPLv3 (open source) and Commercial (proprietary). Contact:[docspoc101@gmail.com]

SHACKLE is a runtime circuit breaker for autonomous AI agents. It answers one question:

Should this agent be allowed to execute this tool with these parameters at this moment?

The protocol defines a deterministic, verifiable decision function backed by 9 mathematical invariants, a language-agnostic message schema, Ed25519-signed append-only audit logging, and a Redis-backed distributed state engine. It operates as a sidecar daemon with gRPC/Unix socket transport, or as an in-process library for single-agent deployments.

SHACKLE is the first open-source runtime circuit breaker for AI agents with cryptographic audit chain-of-custody. This specification is the definitive reference for the SP/1.0 protocol.

Autonomous AI agents execute tools β€” web search, file I/O, API calls, code execution β€” with no runtime oversight. The framework's recursion limit or token cap is the only guardrail. When an agent enters a retry loop (same tool, same error, burning tokens each time), there is no mechanism to detect, intercept, and stop it before the wallet is empty.

This is not hypothetical. Production deployments have documented:

  • Agent infinite loops consuming $6,000+ in API costs before the recursion limit fired
  • Duplicate tool calls repeating 50+ times with no variation
  • Spawned child processes hanging indefinitely while consuming tokens

The industry consensus β€” independently reached by multiple teams in June 2026 β€” is that generation authority is not release authority. The model generates candidates. A separate mediation layer must authorize execution.

SHACKLE is that mediation layer.

Principle Meaning
Deterministic core
decide(state, call) β†’ Verdict is a pure function. Same inputs always produce same outputs.
Daemon as authority
The SHACKLE daemon is the sole source of truth for time, state, and verdicts. Agents are untrusted.
Append-only audit
Every decision is Ed25519-signed and written to an immutable audit log. Chain-of-custody is cryptographically verifiable.
Mathematically verified
9 invariant properties hold under all inputs, proven by property-based testing (Hypothesis, 500+ examples each).
Graceful degradation
Agents function in local/library mode without a daemon. Distributed state is an upgrade path.
Fail-closed
Network failure, daemon crash, or timeout β†’ DENY. No execution without explicit authorization.

This specification covers:

  • The decision function and its 9 mathematical invariants (Β§3)
  • Message schemas and semantics (Β§4)
  • State model (Β§5)
  • Transport bindings (Β§6)
  • Audit and security (Β§7)
  • Compliance framework (Β§8)

This specification does NOT cover:

  • Daemon persistence layer (implementation detail)
  • HITL console UI (presentation concern)
  • Pricing or commercial terms
MODEL A β€” Library Mode (In-Process)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Agent Process          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚ @Guard decorator  β”‚  β”‚
β”‚  β”‚ Local state only  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

MODEL B β€” Sidecar Daemon (Production)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     Unix/gRPC      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Agent Process  β”‚ ◄────────────────► β”‚  SHACKLE Daemon          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚   pre_exec         β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚ Thin      β”‚  β”‚   post_exec        β”‚  β”‚ Policy Engine      β”‚  β”‚
β”‚  β”‚ Client    β”‚  β”‚   register         β”‚  β”‚ - Budgets          β”‚  β”‚
β”‚  β”‚ Shim      β”‚  β”‚   heartbeat        β”‚  β”‚ - Counters         β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚                    β”‚  β”‚ - Circuit Breakers β”‚  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                    β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
                                        β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
                                        β”‚  β”‚ Audit Log          β”‚  β”‚
                                        β”‚  β”‚ Ed25519-signed     β”‚  β”‚
                                        β”‚  β”‚ Append-only        β”‚  β”‚
                                        β”‚  β”‚ Chain-linked       β”‚  β”‚
                                        β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
                                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

MODEL C β€” Distributed (Enterprise)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Agent A  β”‚  β”‚ Agent B  β”‚  β”‚ Agent C  β”‚
β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                   β”‚  gRPC/TLS
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
          β”‚  SHACKLE        β”‚
          β”‚  Daemon Cluster β”‚
          β”‚  Redis (state)  β”‚
          β”‚  Postgres (logs)β”‚
          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚    Policy Language (future)      β”‚  ← DSL for guard rules
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚    Decision Function             β”‚  ← decide(state, call) β†’ Verdict
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚    Message Protocol              β”‚  ← This specification
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚    Transport (Unix/gRPC/WS)      β”‚  ← Binding layer
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The decision function is the heart of SHACKLE. It is a pure function β€” no I/O, no side effects, no allocations in the hot path. It is human-auditable in under 10 minutes. It is under 200 lines of logic.

function decide(
    state: SessionState,
    call: ToolCall,
    config: GuardConfig,
    rng_float: float
) β†’ Verdict
Layer 1: Circuit Breaker
    IF state.circuit_tripped:
        β†’ DENY(CIRCUIT_OPEN)

Layer 2: Nonce Validation (Anti-Replay)
    IF call.nonce IN state.seen_nonces:
        β†’ DENY(POLICY_VIOLATION)

Layer 3: Budget Guard
    IF config.budget_usd > 0:
        IF state.budget_remaining_usd <= 0:
            β†’ DENY(BUDGET_EXHAUSTED)
        IF hitl_mode == ON_THRESHOLD AND fraction <= threshold:
            β†’ HITL("budget threshold reached")
        IF call.cost > state.budget_remaining:
            IF hitl_mode IN (ON_DENY, ALWAYS):
                β†’ HITL("cost exceeds remaining budget")
            β†’ DENY(BUDGET_EXHAUSTED)

Layer 4: Repeat Call Guard
    IF config.max_repeat_calls > 0:
        IF is_repeat(call, state.last_call):
            limit = max_repeat_calls
            IF error_amplification AND has_error_signal(call):
                limit = max(1, limit - 1)
            IF repeat_count >= limit:
                β†’ DENY(MAX_REPEAT_EXCEEDED)

Layer 5: Time Window Guard
    IF config.window_max_calls > 0:
        IF window_count >= window_max_calls:
            β†’ DENY(WINDOW_EXCEEDED)

Layer 6: Global Call Limit
    IF config.max_total_calls > 0 AND total_calls >= max_total_calls:
        β†’ DENY(GLOBAL_LIMIT)

Layer 7: Probabilistic Denial (Adversarial Hardening)
    IF probabilistic_deny AND budget_ratio < 0.2:
        IF rng < deny_jitter_ratio * (1.0 - budget_ratio):
            β†’ DENY(BUDGET_EXHAUSTED, probabilistic=true)

Layer 8: HITL Always
    IF hitl_mode == ALWAYS:
        β†’ HITL("HITL required for all calls")

Default:
    β†’ ALLOW

These 9 properties are verified by property-based testing (Hypothesis, Python) with 500+ randomly generated inputs each. Properties P1-P9 are provably correct.

# Property Formal Statement
P1
Budget monotonically non-increasing βˆ€ calls: budget_after ≀ budget_before
P2
Repeat counts non-decreasing βˆ€ tool: repeat_count never decreases
P3
Once tripped, always tripped circuit_tripped β‡’ all subsequent verdicts = DENY
P4
Budget never negative budget_remaining β‰₯ 0
P5
Repeat limit triggers DENY repeat_count β‰₯ max_repeat_calls β‡’ verdict = DENY
P6
Fresh state ALLOWs first call fresh SessionState + any ToolCall β‡’ ALLOW
P7
Deterministic output identical (state, call, config, rng) β‡’ identical Decision
P8
HITL_ALWAYS produces HITL hitl_mode = ALWAYS ∧ Β¬circuit_tripped β‡’ verdict = HITL
P9
Nonce uniqueness enforced duplicate nonce β‡’ DENY
Verdict Meaning Agent Action
ALLOW
Execute as requested Proceed with tool call
DENY
Block execution Abort, surface deny reason
HITL
Human decision required , await human verdict via HITL console
Reason Trigger
CIRCUIT_OPEN
Circuit breaker was previously tripped
BUDGET_EXHAUSTED
Budget remaining ≀ 0 or cost > remaining
MAX_REPEAT_EXCEEDED
Same tool + same params repeated too many times
WINDOW_EXCEEDED
Too many calls in the current time window
GLOBAL_LIMIT
Session-wide call limit reached
POLICY_VIOLATION
Duplicate nonce (replay attack)
AUTH_FAILED
Authentication failure

SHACKLE detects error signals in tool parameters WITHOUT regex (no ReDoS attack surface). When error_amplification

is enabled, the repeat call threshold is reduced by 1 if the parameters contain known error signals:

Error signals: 401, unauthorized, 403, forbidden, 500, 502, 503,
               504, timeout, connection refused, connection reset,
               permission denied, rate limit, quota exceeded,
               invalid api key, token expired, model not found,
               resource exhausted, deadline exceeded

This catches the "loop of death" β€” agent hits 401, retries, gets 401, retries β€” without waiting for the full repeat threshold.

When probabilistic_deny

is enabled and the agent is below 20% budget, a random factor is introduced:

probability = deny_jitter_ratio Γ— (1.0 βˆ’ budget_ratio)
IF rng < probability:
    β†’ DENY (appears as BUDGET_EXHAUSTED)

This prevents adversarial agents from probing the exact budget threshold and gaming it. The denial appears identical to a real budget exhaustion, making it impossible to distinguish signal from noise.

Every SHACKLE message is wrapped in a Protocol Buffers envelope:

message Envelope {
  string protocol_version = 1;       // "1.0.0"
  string message_id = 2;             // UUIDv7, client-generated
  string correlation_id = 3;         // Request/response pairing
  int64 client_timestamp_ns = 4;     // Client clock (informational)
  int64 server_timestamp_ns = 5;     // Set by daemon on receipt
  bytes hmac = 6;                    // HMAC-SHA256 over payload
  oneof payload {
    PreExecRequest pre_exec = 10;
    PreExecResponse pre_exec_response = 11;
    PostExecNotification post_exec = 12;
    RegisterRequest register = 13;
    RegisterResponse register_response = 14;
    Heartbeat heartbeat = 15;
    HeartbeatAck heartbeat_ack = 16;
    Error error = 17;
  }
}
message RegisterRequest {
  string agent_id = 1;
  string agent_version = 2;
  string framework = 3;              // "crewai" | "autogen" | "langgraph"
  string session_id = 4;             // Optional: resume existing session
  string organization_id = 5;
  string runtime = 6;
  map<string, string> metadata = 7;
}

message RegisterResponse {
  string session_id = 1;
  string daemon_version = 2;
  string negotiated_protocol = 3;
  GuardConfig active_config = 4;
  int64 daemon_time_ns = 5;
}
message PreExecRequest {
  string session_id = 1;
  uint64 call_number = 2;            // Monotonically increasing
  string tool_name = 3;
  bytes tool_params_hash = 4;        // SHA-256 of canonical JSON params
  double estimated_cost_usd = 5;
  string parent_guard_id = 6;        // For nested guard trees
  uint64 nonce = 7;                  // Anti-replay
  map<string, string> tags = 8;
}

message PreExecResponse {
  string session_id = 1;
  uint64 call_number = 2;
  Verdict verdict = 3;
  DenyReason deny_reason = 4;
  string human_readable_reason = 5;
  double budget_remaining_usd = 6;
  int32 repeat_count = 7;
  int64 daemon_time_ns = 8;
  bool probabilistic_deny = 9;
}

Fire-and-forget. No response expected.

message PostExecNotification {
  string session_id = 1;
  uint64 call_number = 2;
  double actual_cost_usd = 3;
  bool success = 4;
  string error_message = 5;
  int64 duration_ms = 6;
  uint64 tokens_in = 7;
  uint64 tokens_out = 8;
  string model_used = 9;
}

Agents SHOULD send heartbeats every 30 seconds. 3 consecutive missed heartbeats β†’ session marked STALE.

message Heartbeat {
  string session_id = 1;
  uint64 last_call_number = 2;
  double local_budget_remaining = 3;  // For drift detection
}

message HeartbeatAck {
  string session_id = 1;
  double daemon_budget_remaining = 2; // Authoritative view
  bool drift_detected = 3;
  int64 daemon_time_ns = 4;
}
service ShackleDaemon {
  rpc Register(RegisterRequest) returns (RegisterResponse);
  rpc PreExec(PreExecRequest) returns (PreExecResponse);
  rpc PostExec(PostExecNotification) returns (google.protobuf.Empty);
  rpc Heartbeat(Heartbeat) returns (HeartbeatAck);
  rpc GetSessionState(GetSessionStateRequest) returns (SessionState);
}
message SessionState {
  string session_id = 1;
  string agent_id = 2;
  string organization_id = 3;
  SessionStatus status = 4;          // ACTIVE | D | TERMINATED | STALE

  // Budget
  double budget_initial_usd = 10;
  double budget_remaining_usd = 11;
  double budget_spent_usd = 12;

  // Counters
  uint64 total_calls = 20;
  map<string, uint32> repeat_counts = 21;   // tool_name β†’ consecutive identical calls
  map<string, uint32> window_counts = 22;   // tool_name β†’ calls in current window

  // Circuit
  bool circuit_tripped = 30;
  string circuit_trip_reason = 31;
  int64 circuit_tripped_at_ns = 32;

  // Time
  int64 window_start_ns = 40;
  uint32 window_duration_s = 41;
  uint32 window_max_calls = 42;

  // Last known
  string last_tool_name = 50;
  bytes last_tool_params_hash = 51;
  int64 last_activity_ns = 52;

  // Metadata
  map<string, string> metadata = 60;
}

enum SessionStatus {
  ACTIVE = 0;
  D = 1;       // HITL in progress
  TERMINATED = 2;
  STALE = 3;        // Heartbeat timeout
}
message GuardConfig {
  // Budget
  double budget_usd = 1;              // 0 = disabled
  BudgetScope budget_scope = 2;       // PER_SESSION | PER_AGENT | PER_ORG

  // Repeat calls
  uint32 max_repeat_calls = 10;       // 0 = disabled
  bool error_amplification = 11;      // Lower threshold on error signals

  // Timeout
  uint32 timeout_seconds = 20;        // Wall-clock timeout. 0 = disabled

  // Time window
  uint32 window_duration_s = 30;
  uint32 window_max_calls = 31;

  // Global limits
  uint32 max_total_calls = 40;        // 0 = disabled

  // Adversarial hardening
  bool probabilistic_deny = 50;
  double deny_jitter_ratio = 51;      // 0.0–1.0

  // HITL
  HitlMode hitl_mode = 60;            // NEVER | ON_DENY | ON_THRESHOLD | ALWAYS
  double hitl_budget_threshold = 61;  // 0.0–1.0

  // Hierarchy
  string parent_guard_id = 70;        // For nested guard trees
}

enum BudgetScope {
  PER_SESSION = 0;
  PER_AGENT = 1;
  PER_ORGANIZATION = 2;
}

enum HitlMode {
  HITL_NEVER = 0;
  HITL_ON_DENY = 1;
  HITL_ON_BUDGET_THRESHOLD = 2;
  HITL_ALWAYS = 3;
}

State is NEVER mutated by the decision function. The daemon applies state changes AFTER the verdict is returned:

After ALLOW: Increment counters, record nonce, update repeat/window countsAfter DENY: Trip circuit breaker (session-wide block)After HITL: Set session status to D, await human verdictAfter PostExec: Update budget (budget_spent += actual_cost)

Path:       /var/run/shackle.sock
Permissions: 0660, owned shackle:agents
Framing:    Length-prefixed protobuf (4-byte big-endian length + protobuf bytes)
SLA:        5ms for pre_exec, 1s for register
Endpoint:   grpc://localhost:9000 or grpcs:// for TLS
Service:    ShackleDaemon (see Β§4.6)
Auth:       mTLS with client certificates
SLA:        5ms for pre_exec, 1s for register
Endpoint:   wss://shackle.example.com/v1/control
Auth:       Bearer token in initial connect
Messages:   JSON-encoded protobuf over text frames
Purpose:    Remote HITL console, cross-network agents
message AuditEntry {
  string entry_id = 1;               // UUIDv7
  int64 timestamp_ns = 2;            // Daemon time
  string session_id = 3;
  string agent_id = 4;
  string organization_id = 5;
  uint64 call_number = 6;
  string tool_name = 7;
  bytes tool_params_hash = 8;
  Verdict verdict = 9;
  DenyReason deny_reason = 10;
  double budget_before_usd = 11;
  double budget_after_usd = 12;
  string operator_id = 13;           // Human operator if HITL override
  bytes signature = 14;              // Ed25519 over fields 1–13
  bytes previous_entry_hash = 15;    // Chain-link to previous entry
}
Property Mechanism
Authenticity
Ed25519 signature over all entry fields
Integrity
Chain-linked via previous_entry_hash (SHA-256)
Immutability
Append-only file (O_APPEND, no seek permitted)
Non-repudiation
Signing key held exclusively by daemon; verification key is public
Verifiability
Any third party can verify the chain with only the public verification key
Component Trust Level Rationale
SHACKLE Daemon Fully trusted
Holds state, writes audit log, issues verdicts
Agent Process Untrusted
May be compromised, buggy, or adversarial
Transport Authenticated + integrity-protected
HMAC on every message
HITL Console Authenticated user
Human decision with audit trail
Threat Mitigation
Replay attack Nonce per call; daemon tracks seen nonces (Β§3.2, Layer 2)
Identity spoofing Registration with org-level auth (Β§4.2)
Clock manipulation Daemon is sole time authority; client timestamps are informational
Budget drift Heartbeat sync with authoritative state (Β§4.5)
Adversarial probing Probabilistic denial near thresholds (Β§3.7)
Audit tampering Append-only file; Ed25519 signatures; chain-linked entries (Β§7.2)
DoS Rate limiting per session; message size cap (1MB)
Protocol parser exploits Separate process for parsing; seccomp sandbox
  • Daemon runs as dedicated user ( shackle

), NOT root - Unix socket owned shackle:agents

, mode 0660 - Audit log file owned shackle:shackle

, mode 0640, append-only - Rate limit: 1,000 pre_exec/sec/session; 10 register/sec/IP

  • Max message size: 1MB
  • Daily log rotation with compression and archival
SOC2 TSC SHACKLE Feature Evidence
CC6.1 Logical Access
Session registration + authentication RegisterRequest with org_id
CC6.3 Security Incidents
Circuit breaker trip events AuditEntry with DENY verdict
CC7.2 System Monitoring
Heartbeat + drift detection Heartbeat/HeartbeatAck messages
CC7.3 Incident Response
HITL console with operator audit trail operator_id in AuditEntry
CC8.1 Change Management
Version negotiation + LTS policy Β§9
A1.2 Availability
Timeout enforcement timeout_seconds in GuardConfig
C1.1 Confidentiality
On-premise daemon, no telemetry Model B/C deployment; local-only
PI1.3 Processing Integrity
Deterministic decision function Β§3.3 properties P1–P9

SHACKLE audit logs are designed to satisfy:

SOC2 Type II auditor requestsISO 27001 Annex A.12.4 (Logging and Monitoring)GDPR Article 30(Records of Processing) β€” for agent actions on personal data** Cyber insurance**underwriting requirements

Protocol versions follow SemVer: MAJOR.MINOR.PATCH

MAJOR: Incompatible message schema changesMINOR: New message types, backward-compatible additionsPATCH: Clarifications, bug fixes, no schema changes

Version Date Changes
1.0.0
2026-06-25 Initial release. 9 invariant properties. Unix/gRPC transport. Ed25519 audit.
  • SP/1.0 is the LTS version, guaranteed support through 2031
  • New major versions coexist with previous LTS for minimum 2 years
  • Audit log schema is append-only: fields added, never removed
  • Deprecated fields marked with annotation, never deleted
Client β†’ Daemon: protocol_version = "1.2.0"
Daemon checks:   can support up to 1.0.0
Daemon β†’ Client: negotiated_protocol = "1.0.0"

No compatible version β†’ Error with code PROTOCOL_VERSION_MISMATCH

.

The Python reference implementation lives at:

https://github.com/Fame510/SHACKLE

Component File Status
Decision function v2/spec/decide.py
βœ… Production (187 lines)
Property-based tests v2/tests/test_decide_properties.py
βœ… 18/18 passing
Protocol definitions v2/protocol/shackle.proto
βœ… Complete
Service definitions v2/protocol/shackle_service.proto
βœ… Complete
CI pipeline .github/workflows/ci.yml
βœ… Configured
TypeScript library v2/ts/
βœ… Published
Docker image Dockerfile
βœ… Multi-stage
from shackle import Guard

@Guard(budget=0.50, max_repeat_calls=3, timeout_seconds=180)
def my_agent():
    pass

Install: pip install git+https://github.com/Fame510/SHACKLE.git

1.  Agent β†’ Daemon: REGISTER(agent_id="research-bot", framework="crewai")
2.  Daemon β†’ Agent: REGISTER_RESPONSE(session_id="s_01", config={budget:0.50, max_repeat:3})

3.  Agent β†’ Daemon: PRE_EXEC(call=1, tool="web_search", hash=0xDEAD, cost=0.002)
4.  Daemon β†’ Agent: PRE_EXEC_RESPONSE(verdict=ALLOW, budget_remaining=0.498)

5.  Agent: [executes web_search]
6.  Agent β†’ Daemon: POST_EXEC(call=1, actual_cost=0.0015, success=true)

7.  Agent β†’ Daemon: PRE_EXEC(call=2, tool="web_search", hash=0xDEAD, cost=0.002)
8.  Daemon β†’ Agent: PRE_EXEC_RESPONSE(verdict=ALLOW, budget_remaining=0.496, repeat_count=1)

    ... agent repeats 2 more times ...

9.  Agent β†’ Daemon: PRE_EXEC(call=4, tool="web_search", hash=0xDEAD, cost=0.002)
10. Daemon β†’ Agent: PRE_EXEC_RESPONSE(verdict=DENY, reason=MAX_REPEAT_EXCEEDED, repeat_count=3)

11. Daemon: [writes AuditEntry to append-only log]
12. Daemon: [trips circuit breaker for session β€” all subsequent calls DENY]
Code Description
PROTOCOL_VERSION_MISMATCH
No compatible protocol version
SESSION_NOT_FOUND
Unknown or expired session_id
AUTHENTICATION_FAILED
Invalid credentials or duplicate nonce
RATE_LIMITED
Too many requests
MESSAGE_TOO_LARGE
Exceeds 1MB limit
DAEMON_UNAVAILABLE
Internal daemon error
ORGANIZATION_QUOTA_EXCEEDED
Org-level limit reached
PARENT_GUARD_DENIED
Parent guard rejected the call
Term Definition
Agent
An autonomous AI process that executes tools
Circuit Breaker
Once tripped, all subsequent calls are DENY
Daemon
The SHACKLE server process β€” sole authority for state and verdicts
Guard
A configured policy (budget, repeat limit, timeout) applied to an agent
HITL
Human-in-the-Loop β€” manual authorization step
Nonce
A number used once β€” anti-replay mechanism
Tool Call
A single invocation of an agent tool (API, file I/O, code exec)
Verdict
The decision: ALLOW, DENY, or HITL

SP/1.0 β€” Sovereign Logic, June 2026. Licensed under CC-BY 4.0.

Reference implementation: AGPLv3 + Commercial. Contact: docspoc101@gmail.com

── more in #ai-agents 4 stories Β· sorted by recency
── more on @sovereign logic 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/sp-1-0-deterministic…] indexed:0 read:16min 2026-07-26 Β· β€”