Install and use the framework-agnostic Contro1 Python SDK to request human approvals or input, verify signed webhooks, log autonomous actions, and fetch audit evidence.
Use the centcom Python package when your agent runtime, backend service, or workflow worker runs in Python.
Use the integration skill
Copy this skill link into your code agent to add Python SDK and Contro1 to your system.
Use create_protocol_request when an action must pause for human approval.
Use request_type input when an agent needs a free-text answer from a human.
Use log_action for allowed autonomous actions that still need durable evidence.
Verify signed webhooks before resuming any production action.
Install
Use the general Python SDK when your agent, service, worker, tool runner, or webhook bridge is written in Python. It is not tied to Claude Code or any other framework. The same client handles approval and human-input requests, audit records, read APIs, and webhook verification helpers. Runtime-specific connectors are thin adapters on top of the same API.
import os
from centcom import CentcomClient
client = CentcomClient(
api_key=os.environ["CENTCOM_API_KEY"],
base_url=os.environ.get("CENTCOM_BASE_URL"),
)
Create an approval request
Call create_protocol_request at the point where a risky action is ready but has not executed yet. Use external_request_id for idempotency and correlation_id to group the full business case.
Build context at the gate: copy the exact tool input your code intercepted (machine-observed), attach what triggered the run, and pass the agent's justification by making reason a required parameter of the risky tool. Label model-written text as agent-reported - it informs the reviewer but never changes routing or risk_level.
Use request_type input when the workflow needs information rather than permission. The human response is required and returns as decision_type respond. This is different from an optional or policy-required comment attached to Approve or Reject.
human_input.py
request = client.create_protocol_request({
"title": "Which region should this deployment use?",
"request_type": "input",
"source": {"integration": "deployment-agent", "run_id": run_id},
"context": {
"action": {"tool": "configure_deployment", "input": {"service": "billing-api"}},
"machine_observed": {"available_regions": ["us-east-1", "eu-west-1"]},
},
"continuation": {"mode": "instruction"},
})
response = client.wait_for_protocol_response(request["request_id"])
if response["decision_type"] != "respond":
raise RuntimeError("Human input was not provided")
region = response["structured_response"]["value"]
Verify the webhook
Webhook-first is the production path. Verify the signature and timestamp before trusting status, reviewer comments, or structured response data.
webhook.py
from centcom import verify_webhook
ok = verify_webhook(raw_body, signature, timestamp, os.environ["CENTCOM_WEBHOOK_SECRET"])
if not ok:
raise PermissionError("Invalid Contro1 webhook signature")
if payload["status"] != "approved":
abort_action()
else:
resume_action(payload["response"])
Log autonomous actions
Approval requests already store the human decision. Use log_action for actions that were allowed to run automatically but still need searchable evidence.
Beyond the approval call, attach identity, a run trace, the tools you invoked, and the context you retrieved. Each field is optional — add what you have. The verified identity always comes from your API key; a caller-supplied actor.agent_id is recorded as a claimed sub-agent until an admin verifies it.
trace_id / parent_trace_id — link one run (and sub-agent runs) into a single trace.
tool_calls[] — what the agent tried to do, so reviewers see the actions.
retrieved_context[] — the data the decision was based on (RAG provenance).
Then export a signed evidence packet from GET /requests/:id/evidence.
Send full traceability
# Same approval call you already make — now with full traceability.
client.requests.create(
request_type="approval",
title="Refund $4,200 to customer 8831",
source={"integration": "api"},
actor={"agent_id": "billing-agent", "agent_name": "Billing Agent"}, # claimed sub-agent
trace_id=f"trc_{run_id}", # link every step of this run
tool_calls=[{"name": "lookup_order", "outcome": "success"}],
retrieved_context=[{"source": "policy:refunds", "uri": "kb://policy/refunds"}],
continuation={"mode": "decision"},
)
The signed webhook is cryptographic proof of a human decision. Verify it inside the system that executes the action - not inside the agent. Any tool that must never run without human sign-off (payments, deploys, data deletion) should refuse to act without a verified approval; that way no agent, including shadow agents nobody registered, can trigger it by skipping Contro1.
Verify the signature and reject timestamps older than 5 minutes (replay protection; the timestamp marks callback delivery, not request creation, so long SLAs are unaffected).
Bind the approval to the exact action parameters via metadata / correlation_id - never treat "an approval arrived" as permission for a different action.
Execute each request_id exactly once (idempotency on your side).
When in doubt, confirm state directly with GET /v1/requests/:id using a read-only API key.
When should I use the Python SDK instead of a framework connector?
Use the Python SDK for custom Python services, workers, and agents. Use a framework connector when you are inside LangGraph, CrewAI, OpenAI Agents SDK, or another supported runtime with its own pause/resume pattern.
Do approval requests automatically create evidence?
Yes. The request stores context, routing, decision, reviewer, timestamps, callback state, and protocol response. Use audit records for additional autonomous or post-approval events.
Use Contro1 audit records to log actions that agents are authorized to run autonomously, and correlation_id to connect requests and logs into one case timeline.