Skip to main content

Human Approval

Human approval tracking provides verifiable proof that a human reviewed and approved an agent’s action before or after execution.

Why Human Approval?

Even the most capable AI agents need human oversight for:
  • High-risk decisions — Financial transactions, account changes, legal documents
  • Compliance requirements — Regulations requiring human review
  • Quality assurance — Catching edge cases AI might miss
  • Accountability — Clear audit trail of who approved what

Basic Usage

from treeship_sdk import Treeship

ts = Treeship(api_key='your-key')

# Create attestation with human approval
result = ts.attest(
    action="Approved refund of $5,000 for order #12345",
    human_approved=True,
    human_approver_hash=ts.hash("finance-manager@company.com")
)

print(f"Human Approved: {result.human_approved}")

Privacy-Preserving Approvals

The human_approver_hash is a SHA256 hash — the actual approver identity is never stored:
# Only the hash is stored - original email is private
approver_hash = ts.hash("jane.doe@company.com")
# approver_hash = "a1b2c3d4..." (can verify identity locally)

Approval Workflows

Pre-Approval (Human First)

Human approves before agent executes:
def process_with_approval(request, approver_email):
    # 1. Get human approval
    approval = get_human_approval(request)
    
    if not approval.granted:
        return {"error": "Approval denied"}
    
    # 2. Execute action
    result = execute_action(request)
    
    # 3. Record with attestation
    ts.attest(
        action=f"Executed: {request.description}",
        human_approved=True,
        human_approver_hash=ts.hash(approver_email),
        metadata={
            "approval_time": approval.timestamp,
            "approval_notes": approval.notes
        }
    )

Post-Approval (Review After)

Agent executes, human reviews afterward:
def execute_with_review(request):
    # 1. Execute immediately
    result = execute_action(request)
    
    # 2. Create initial attestation (not yet approved)
    attestation = ts.attest(
        action=f"Executed: {request.description}",
        human_approved=False
    )
    
    # 3. Queue for human review
    queue_for_review(attestation.attestation_id)
    
    return result

# Later, when human reviews:
def approve_action(attestation_id, approver_email):
    # Record approval as new attestation referencing the original
    ts.attest(
        action=f"Human approved attestation {attestation_id}",
        human_approved=True,
        human_approver_hash=ts.hash(approver_email),
        metadata={"original_attestation": attestation_id}
    )

Threshold-Based Approval

Require human approval based on risk:
def process_transaction(amount, recipient):
    requires_approval = (
        amount > 1000 or  # High value
        recipient not in approved_vendors or  # New vendor
        is_international(recipient)  # Cross-border
    )
    
    if requires_approval:
        approval = request_human_approval({
            "amount": amount,
            "recipient": recipient,
            "reason": "Threshold exceeded"
        })
        
        if not approval.granted:
            raise ApprovalDenied()
        
        ts.attest(
            action=f"Transfer ${amount} to {recipient}",
            human_approved=True,
            human_approver_hash=ts.hash(approval.approver)
        )
    else:
        ts.attest(
            action=f"Transfer ${amount} to {recipient}",
            human_approved=False  # Auto-approved under threshold
        )

Multi-Approver Workflows

For actions requiring multiple approvals:
def process_large_payment(amount, recipient, approvers):
    # Collect all approvals
    approval_hashes = [ts.hash(a.email) for a in approvers]
    
    ts.attest(
        action=f"Multi-approved payment: ${amount} to {recipient}",
        human_approved=True,
        human_approver_hash=ts.hash(",".join(sorted(approval_hashes))),
        metadata={
            "approver_count": len(approvers),
            "approval_threshold": 2,
            "individual_hashes": approval_hashes
        }
    )

Querying Approved Actions

Filter agent feed by approval status:
# Get agent's attestation history
agent_data = ts.get_agent("my-agent")

# Filter for human-approved actions
approved = [a for a in agent_data["attestations"] if a.get("human_approved")]
pending = [a for a in agent_data["attestations"] if not a.get("human_approved")]

print(f"Approved: {len(approved)}, Pending Review: {len(pending)}")

Compliance Reporting

Generate compliance reports showing human oversight:
def generate_compliance_report(agent_slug, start_date, end_date):
    attestations = ts.get_agent(agent_slug)["attestations"]
    
    report = {
        "total_actions": len(attestations),
        "human_approved": sum(1 for a in attestations if a.get("human_approved")),
        "auto_approved": sum(1 for a in attestations if not a.get("human_approved")),
        "approval_rate": None
    }
    
    report["approval_rate"] = report["human_approved"] / report["total_actions"]
    
    return report

Best Practices

Define Clear Thresholds

Document when human approval is required vs. auto-approved.

Use Consistent Hashing

Always hash the same identifier format (email, employee ID).

Include Context

Add approval reason and notes in metadata for audit trails.

Set Time Limits

Define SLAs for human review to prevent bottlenecks.