Actually Smart Contractsalpha

Status: the sandbox runs today live. The SDK and API on this page are planned planned.

Docs

Guard agents and models

Put a jury in front of the few actions that can hurt you: spending, sending and what a model says.

Be plain about latency: a jury takes seconds, so it guards actions, not keystrokes.

1. Before a risky tool call

Guard only the tools that spend, send or delete. Every other tool runs as normal. Outcomes are allow, ask or deny.

asc.requestRuling() in a tool hookTypeScriptplanned
const GUARDED = new Set(['purchase', 'pay_invoice', 'start_subscription']);

async function beforeToolCall(call) {
  if (!GUARDED.has(call.name)) return { run: true };     // every other tool runs as normal
  const ruling = await asc.requestRuling({
    asc: 'asc_agent_spending_v1',
    jury: { size: 3, quorum: 2, tier: 'fast' },
    action: { type: 'agent_tool_call', tool: call.name, input: call.input },
    evidence: { task, budget, vendor },                  // the owner's words, not the agent's summary
  });
  if (ruling.outcome === 'allow') return { run: true };
  if (ruling.outcome === 'ask') return { run: false, askOwner: ruling.rulesBroken };
  return { run: false, toolResult: 'Blocked by spending rules' };
}

Full sample: An agent's spending limits.

2. Before a message leaves

Outcomes are send, redact or block.

asc.request_ruling() before sendPythonplanned
ruling = asc.request_ruling(
    asc="asc_customer_data_v1",
    jury={"size": 3, "quorum": 2, "tier": "fast"},
    action={"type": "agent_outbound_message", "to": to, "body": body},
    evidence={"ticket": ticket, "customer": customer_id},
)
if ruling.outcome == "send":
    send(to, body)
elif ruling.outcome == "redact":
    send(to, asc.redact(body, ruling))     # flagged lines removed
else:
    escalate(ticket, ruling)               # block: a human takes it

Full sample: A support agent's data rules.

3. Auditing a model

A batch of logged answers is checked nightly, and a signed report is published. A ruling takes 20 to 60 seconds, so this is for audits, not live chat.

asc.request_rulings() in a nightly jobPythonplanned
rulings = asc.request_rulings(
    asc="asc_model_behavior_v1",
    jury={"size": 5, "quorum": 4, "tier": "standard"},
    requests=[{"action": {"type": "model_output", "id": row.id},
               "evidence": {"prompt": row.prompt, "answer": row.answer}} for row in batch],
)
failures = [r for r in rulings if r.outcome == "fail"]
asc.publish_report("asc_model_behavior_v1", {"checked": len(rulings), "failed": len(failures)})

Full sample: Model behavior audit.