Skip to main content

Your First Governed Action

FieldValue
Document IDASCEND-START-002
Version1.0.0
Last UpdatedDecember 19, 2025
AuthorAscend Engineering Team
PublisherOW-KAI Technologies Inc.
ClassificationEnterprise Client Documentation
ComplianceSOC 2 CC6.1/CC6.2, PCI-DSS 7.1/8.3, HIPAA 164.312, NIST 800-53 AC-2/SI-4

Reading Time: 10 minutes | Skill Level: Beginner

Overview

This tutorial walks you through submitting your first governed action, understanding the response, and handling different decision outcomes. By the end, you'll have a complete working integration.

Prerequisites

Before you begin, ensure you have:

  • Completed the Quick Start guide
  • An API key configured
  • Python 3.8+ with ascend-sdk installed

Step 1: Set Up Your Environment

Create a new Python file for this tutorial:

# tutorial.py
import os
from ascend import AscendClient, AgentAction

# Load API key from environment (recommended)
API_KEY = os.environ.get("ASCEND_API_KEY", "owkai_your_key_here")

# Initialize the client
# Source: sdk/ascend-sdk-python/ascend/client.py:324
client = AscendClient(
api_key=API_KEY,
agent_id="tutorial-agent",
agent_name="Tutorial Agent",
environment="sandbox" # Use sandbox for testing
)

print("Client initialized successfully!")
Use Environment Variables

Never hardcode API keys. Use environment variables:

export ASCEND_API_KEY="owkai_your_key_here"

Step 2: Create a Low-Risk Action

Let's start with a simple, low-risk action that will be auto-approved:

# Low-risk action: Reading public data
# Source: sdk/ascend-sdk-python/ascend/client.py:368
low_risk_action = AgentAction(
action_type="database_read",
description="Read list of public product categories",
parameters={
"table": "product_categories",
"operation": "SELECT",
"columns": ["id", "name", "description"],
"data_classification": "public"
}
)

# Submit the action
result = client.submit_action(low_risk_action)

print(f"""
LOW-RISK ACTION RESULT
======================
Action ID: {result.action_id}
Decision: {result.decision}
Risk Score: {result.risk_score}
Risk Level: {result.risk_level}
""")

Expected Output:

LOW-RISK ACTION RESULT
======================
Action ID: act_abc123xyz
Decision: APPROVED
Risk Score: 2.1
Risk Level: LOW

Understanding Low-Risk Response

For low-risk actions, ASCEND:

  1. Evaluates the risk (score 2.1 = LOW)
  2. Checks Smart Rules (none triggered)
  3. Auto-approves based on workflow config
  4. Logs to audit trail
  5. Returns immediately

Step 3: Create a Medium-Risk Action

Now let's try an action that requires more scrutiny:

# Medium-risk action: Accessing customer data
medium_risk_action = AgentAction(
action_type="database_read",
description="Read customer contact information for support ticket",
parameters={
"table": "customers",
"operation": "SELECT",
"columns": ["id", "name", "email", "phone"],
"data_classification": "pii",
"purpose": "customer_support"
},
context={
"ticket_id": "TICKET-12345",
"requester": "support-agent@company.com"
}
)

result = client.submit_action(medium_risk_action)

print(f"""
MEDIUM-RISK ACTION RESULT
=========================
Action ID: {result.action_id}
Decision: {result.decision}
Risk Score: {result.risk_score}
Risk Level: {result.risk_level}
CVSS Vector: {result.cvss_vector}
""")

# For medium risk, decision might be PENDING
if result.decision == "PENDING":
print(f"Pending Approvers: {result.pending_approvers}")
print(f"Approval URL: {result.approval_url}")

Expected Output:

MEDIUM-RISK ACTION RESULT
=========================
Action ID: act_def456xyz
Decision: APPROVED (or PENDING in strict mode)
Risk Score: 5.3
Risk Level: MEDIUM
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N

Step 4: Create a High-Risk Action

High-risk actions typically require approval:

# High-risk action: Modifying customer data
high_risk_action = AgentAction(
action_type="database_write",
description="Update customer billing address",
parameters={
"table": "customers",
"operation": "UPDATE",
"affected_rows": 1,
"columns": ["billing_address", "billing_city", "billing_zip"],
"data_classification": "pii"
},
context={
"customer_id": "cust_789",
"change_reason": "Customer requested address update",
"verified_by": "phone_verification"
}
)

result = client.submit_action(high_risk_action)

print(f"""
HIGH-RISK ACTION RESULT
=======================
Action ID: {result.action_id}
Decision: {result.decision}
Risk Score: {result.risk_score}
Risk Level: {result.risk_level}
""")

Expected Output (Pending Approval):

HIGH-RISK ACTION RESULT
=======================
Action ID: act_ghi789xyz
Decision: PENDING
Risk Score: 7.2
Risk Level: HIGH

Step 5: Handle Pending Decisions

When an action requires approval, you have several options:

Option A: Wait for Decision

# Wait up to 5 minutes for approval
# Source: sdk/ascend-sdk-python/ascend/client.py:474
final_result = client.wait_for_decision(
action_id=result.action_id,
timeout_seconds=300, # 5 minutes
poll_interval=5 # Check every 5 seconds
)

if final_result.decision == "APPROVED":
print("Approval received - proceeding with action")
# Execute your action here
elif final_result.decision == "DENIED":
print(f"Action denied: {final_result.denial_reason}")
elif final_result.decision == "TIMEOUT":
print("Approval timed out - action not executed")

Option B: Check Status Later

# Store the action ID and check later
action_id = result.action_id

# ... later in your code or another process ...

# Source: sdk/ascend-sdk-python/ascend/client.py:451
status = client.get_action_status(action_id)
print(f"Current status: {status.decision}")

Option C: Use Webhooks

Configure a webhook to receive approval notifications:

# Configure webhook for your agent
# Source: sdk/python/owkai_sdk/client.py:984
client.configure_webhook(
url="https://your-app.com/webhooks/ascend",
events=["action.approved", "action.denied"],
secret="your_webhook_secret"
)

Step 6: Handle Denied Actions

Sometimes actions will be denied. Handle this gracefully:

# Example: Action denied by Smart Rule
denied_action = AgentAction(
action_type="database_delete",
description="Delete inactive user accounts",
parameters={
"table": "users",
"operation": "DELETE",
"affected_rows": 150
}
)

result = client.submit_action(denied_action)

if result.decision == "DENIED":
print(f"""
ACTION DENIED
=============
Reason: {result.denial_reason}
Rule ID: {result.rule_id}
Rule Name: {result.rule_name}

Suggested actions:
1. Review the triggering rule
2. Request an exception if appropriate
3. Modify the action to comply with policy
""")

Example Denial Response:

ACTION DENIED
=============
Reason: Bulk delete operations require manager approval
Rule ID: rule_no_bulk_delete
Rule Name: Block Bulk Deletions

Suggested actions:
1. Review the triggering rule
2. Request an exception if appropriate
3. Modify the action to comply with policy

Step 7: Complete Example

Here's a complete, production-ready example:

#!/usr/bin/env python3
"""
Complete ASCEND Integration Example
Demonstrates proper error handling and decision flow
"""
import os
import sys
from ascend import AscendClient, AgentAction
from ascend.exceptions import (
AscendConnectionError,
AscendAuthenticationError,
AscendRateLimitError
)

def main():
# Initialize client
try:
client = AscendClient(
api_key=os.environ["ASCEND_API_KEY"],
agent_id="production-agent",
agent_name="Production Data Agent",
environment="production"
)
except AscendAuthenticationError:
print("ERROR: Invalid API key")
sys.exit(1)

# Create action
action = AgentAction(
action_type="database_read",
description="Generate monthly sales report",
parameters={
"table": "orders",
"operation": "SELECT",
"date_range": "last_30_days"
}
)

# Submit and handle result
try:
result = client.submit_action(action)

if result.decision == "APPROVED":
print(f"✅ Approved (Risk: {result.risk_level})")
execute_report_generation()

elif result.decision == "PENDING":
print(f"⏳ Pending approval from: {result.pending_approvers}")
# Option 1: Wait
final = client.wait_for_decision(result.action_id, timeout_seconds=300)
if final.decision == "APPROVED":
execute_report_generation()
else:
print(f"❌ Not approved: {final.decision}")

elif result.decision == "DENIED":
print(f"❌ Denied: {result.denial_reason}")

except AscendConnectionError:
print("ERROR: Could not connect to ASCEND")
# Implement fallback behavior
except AscendRateLimitError:
print("ERROR: Rate limit exceeded, retry later")

def execute_report_generation():
"""Your actual business logic here"""
print("Executing report generation...")
# ... your code ...

if __name__ == "__main__":
main()

Verification

Run these commands to verify your integration:

# Set your API key
export ASCEND_API_KEY="owkai_your_key_here"

# Run the tutorial script
python tutorial.py

# Check the audit log via CLI
ascend actions list --agent-id tutorial-agent --limit 10

Expected output:

ID              TYPE            RISK    DECISION   TIME
act_abc123xyz database_read LOW APPROVED 2 min ago
act_def456xyz database_read MEDIUM APPROVED 1 min ago
act_ghi789xyz database_write HIGH PENDING just now

Troubleshooting

IssueCauseSolution
ASCEND_API_KEY not setMissing environment variableRun export ASCEND_API_KEY="..."
All actions DENIEDOverly strict rulesCheck Smart Rules in dashboard
All actions PENDINGNo auto-approve configuredConfigure workflow for low-risk
Timeout errorsNetwork or rate limitingCheck connectivity, implement retry

Next Steps

Congratulations! You've successfully integrated with ASCEND. Continue your journey:


Document Version: 1.0.0 | Last Updated: December 2025