Learning Objectives
By the end of this module, you will be able to:
- Install the VCP SDK (Python or TypeScript)
- Connect to the Creed Space API
- Make a
decidecall that evaluates a tool action against a constitution - Interpret the decision result (ALLOW, DENY, REQUIRE_HUMAN)
- Verify a decision token
3.1 — Installation
Python:
pip install creed-sdk TypeScript:
npm install @creed-space/sdk 3.2 — Getting Your API Key
- Sign up at creed.space
- Navigate to Dashboard → API Keys → Create New Key
- Copy your key (format:
crd_test_...for sandbox,crd_live_...for production)
3.3 — Your First Decision
The core VCP operation is decide — "Should this action be allowed, given these values?"
Note: The Python SDK is async. All examples use
awaitand should be run inside anasyncfunction or withasyncio.run().
Python:
import asyncio
from creed_sdk import CreedClient
async def main():
client = CreedClient(api_key="crd_test_your_key_here")
result = await client.decide(
tool_name="send_email",
arguments={"to": "patient@example.com", "body": "Your test results are..."},
constitution_id="healthcare_v3",
)
if result.decision == "ALLOW":
print(f"Approved. Risk score: {result.risk.score}")
print(f"Decision token: {result.decision_token}")
elif result.decision == "DENY":
print(f"Denied. Reasons: {result.reasons}")
print(f"Guidance: {result.guidance}")
elif result.decision == "REQUIRE_HUMAN":
print(f"Needs human review. Review ID: {result.review_id}")
await client.close()
asyncio.run(main()) TypeScript:
import { createClient } from '@creed-space/sdk';
const client = createClient({ apiKey: 'crd_test_your_key_here' });
const result = await client.decide({
toolName: 'send_email',
arguments: { to: 'patient@example.com', body: 'Your test results are...' },
constitutionId: 'healthcare_v3',
});
console.log(result.decision); // "ALLOW" | "DENY" | "REQUIRE_HUMAN" 3.4 — Understanding the Response
Every decision result includes these common fields:
| Field | Description |
|---|---|
decision | The verdict: ALLOW, DENY, or REQUIRE_HUMAN |
run_id / runId | Unique identifier for this evaluation run |
action_id / actionId | Identifier for this specific action within the run |
args_hash / argsHash | SHA-256 hash of the arguments (for later verification) |
risk.score | Numeric risk assessment (0.0–1.0) |
risk.labels | Categorical risk labels that triggered |
ALLOW-specific fields:
| Field | Description |
|---|---|
decision_token / decisionToken | Signed JWT proof of this decision (use for downstream authorisation) |
expires_at / expiresAt | When the decision token expires |
DENY-specific fields:
| Field | Description |
|---|---|
reasons | List of strings explaining why the action was denied |
guidance | Dictionary of suggestions for how to modify the action to be allowed |
3.5 — Verifying a Decision
Decision tokens prove that a specific action was evaluated and approved. Downstream systems can verify this without re-evaluating:
Python:
auth = await client.authorize(
decision_token=result.decision_token,
tool_name="send_email",
args_hash=result.args_hash,
)
if auth.authorized:
# Proceed with the action — it's been vetted
send_the_email()
else:
print(f"Token invalid: {auth.error}") TypeScript:
const auth = await client.authorize({
decisionToken: result.decisionToken,
toolName: 'send_email',
argsHash: result.argsHash,
});
if (auth.authorized) {
// Proceed — action has been vetted
sendTheEmail();
} else {
console.log(`Token invalid: ${auth.error}`);
} 3.6 — Callback-Based Flow
Both SDKs support callback-based flow control, allowing you to handle each decision type with dedicated functions:
Python:
result = await client.decide(
tool_name="send_email",
arguments={"to": "patient@example.com", "body": "Results..."},
constitution_id="healthcare_v3",
on_allow=lambda d: print(f"Authorized: {d.decision_token}"),
on_deny=lambda d: print(f"Denied: {d.reasons}"),
on_require_human=lambda d: print(f"Human review needed"),
) TypeScript:
const result = await client.decide({
toolName: 'send_email',
arguments: { to: 'patient@example.com', body: 'Results...' },
constitutionId: 'healthcare_v3',
onAllow: (d) => console.log('Authorized:', d.decisionToken),
onDeny: (d) => console.log('Denied:', d.reasons),
onRequireHuman: (d) => console.log('Human review needed'),
}); Exercise
- Use the VCP Inspector to decode a sample CSM-1 token and understand what constitution it represents.
- Make three
decidecalls with different actions — one that should be allowed, one that should be denied, and one that's ambiguous. Observe how the constitution shapes the decisions.
VCP integration starts with a single API call. decide is the fundamental operation — everything else builds on it.
Try It
Use the Token Playground to experiment with CSM-1 tokens interactively, or explore the Gentian demo to see VCP decisions in action.