Documentation
Everything you need to instrument your AI agent with causal tracing. Get a key, log events, and trace any outcome back to its root cause.
Quickstart - 60 seconds
Get your first event flowing without installing anything.
Step 1: Get a free API key at /signup
Step 2: Run this in your terminal:
curl -X POST https://iknowhy.ai/api/events \
-H "Authorization: Bearer cwy_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "hello_world", "payload": {"msg": "it works!"}}'Step 3: Check your dashboard - the event appears within seconds.
That is it. Now install the SDK for full Python integration:
pip install iknowhyGetting Started
You can be up and running in under a minute. Three steps:
-
Install the SDK
pip install iknowhy -
Get an API key
Sign up at iknowhy.ai/signup to get a free key, or generate one from your account page. Keys look like
cwy_.... -
Log your first event
# Connect and log one event from iknowhy import CausewayClient c = CausewayClient(api_key="cwy_your_key_here") event_id = c.log("user_request", payload={"task": "search docs"})
Authentication
All API requests require a Bearer token in the Authorization header. Pass your API key like this:
Authorization: Bearer cwy_your_key_hereKey types
| Type | Format | Use |
|---|---|---|
| API Key | cwy_... | Authenticate SDK calls and direct API requests |
| Admin Key | Set via ADMIN_KEY env var | Create new API keys via POST /api/keys |
Log an Event
POST /api/events - Create a causal event node. Every event can optionally reference one or more cause events to build the causal DAG.
Request fields
tool_call, decision.
Response
{
"event_id": "evt_abc123...",
"name": "tool_call",
"ts": 1718300400.123
}curl example
curl -X POST https://iknowhy.ai/api/events \
-H "Authorization: Bearer cwy_your_key" \
-H "Content-Type: application/json" \
-d '{
"name": "tool_call",
"payload": {"tool": "web_search", "query": "revenue Q4"},
"session_id": "sess_001",
"cause_ids": ["evt_parent_id"]
}'Python example
from iknowhy import CausewayClient
c = CausewayClient(api_key="cwy_your_key")
# Log a chain: request -> decision -> tool call -> result
req = c.log("user_request", payload={"task": "search"}, session_id="s1")
dec = c.log("decision", payload={"action": "use web_search"}, cause_ids=[req], session_id="s1")
call = c.log("tool_call", payload={"tool": "web_search"}, cause_ids=[dec], session_id="s1")
res = c.log("tool_result", payload={"status": "ok", "n": 3}, cause_ids=[call], session_id="s1")Query Events
GET /api/events - Retrieve events with optional filters.
Query parameters
| Param | Type | Default | Description |
|---|---|---|---|
session_id | string | - | Filter by session |
name | string | - | Filter by event name |
limit | int | 100 | Max events to return (1-1000) |
Response
{
"events": [
{
"id": "evt_abc123",
"name": "tool_call",
"session_id": "sess_001",
"payload": {"tool": "web_search"},
"cause_ids": ["evt_parent"],
"ts": 1718300400.123,
"tags": {}
}
]
}Causal Chains
GET /api/chain/{event_id} - Walk backwards through the causal DAG from any event to its root cause. This is the core feature of iKnowhy: given any outcome, you can trace exactly what caused it.
The chain follows cause_ids links recursively. If event C was caused by B, and B was caused by A, querying the chain for C returns [A, B, C] - the full causal ancestry in order.
Response
{
"chain": [
{"id": "evt_001", "name": "user_request", "ts": 1718300400.0, ...},
{"id": "evt_002", "name": "decision", "ts": 1718300400.5, ...},
{"id": "evt_003", "name": "tool_call", "ts": 1718300401.0, ...}
],
"length": 3
}Example
# Trace why a tool was called
chain = c.chain("evt_003")
for event in chain:
print(f"{event['name']} -> {event.get('payload', {})}")Constraint Violations
GET /api/violations - Check the last 500 events for built-in causal constraint violations. Constraints enforce structural rules that healthy agent behaviour should follow.
Built-in constraints
| Constraint | Rule |
|---|---|
tool_call_needs_result | Every tool_call must have a corresponding tool_result that references it |
error_needs_handling | Every error event must be followed by an error_handling event |
external_send_needs_decision | Every external_send must be caused by a decision event |
Response
{
"violations": [
{
"constraint": "tool_call_needs_result",
"event_id": "evt_abc123",
"description": "tool_call has no matching tool_result"
}
],
"count": 1
}Sessions
GET /api/sessions - List all sessions for your tenant. Returns the 100 most recent sessions with event counts and timestamps.
Response
{
"sessions": [
{
"session_id": "sess_001",
"started_at": 1718300400.0,
"ended_at": 1718301000.0,
"event_count": 42
}
]
}Python SDK
The CausewayClient class wraps the REST API for convenient Python usage. Install with pip install iknowhy.
Constructor
from iknowhy import CausewayClient
c = CausewayClient(
api_key="cwy_your_key", # required
# base_url defaults to https://iknowhy.ai
)Methods
log(name, payload=None, session_id=None, cause_ids=None, tags=None) -> str
Log a causal event. Returns the event_id.
eid = c.log("decision", payload={"action": "approve"}, session_id="s1")
# Returns: "evt_abc123..."events(session_id=None, name=None, limit=100) -> list
Fetch events with optional filters.
all_calls = c.events(name="tool_call", limit=50)chain(event_id) -> list
Get the full causal ancestry for an event.
ancestry = c.chain("evt_abc123")
for e in ancestry:
print(e["name"], e["payload"])violations() -> list
Check for constraint violations across recent events.
issues = c.violations()
if issues:
print(f"Found {len(issues)} violations")sessions() -> list
List all sessions.
for s in c.sessions():
print(s["session_id"], s["event_count"])Platform Setup - Permanent Auto-Logging
One command detects and wires every AI tool on your machine. After setup, every session logs automatically - no prompting, no manual steps per session, no configuration per conversation.
Install and wire everything at once
pip install iknowhy
iknowhy setup --key cwy_your_key_herePlatform coverage
| Platform | What gets wired | Permanent? |
|---|---|---|
| Claude Desktop | Adds MCP server to claude_desktop_config.json. Restart Desktop to activate. | Yes |
| Claude Code | Writes ~/.claude/mcp.json + auto-logging rules to ~/.claude/CLAUDE.md | Yes |
| Cursor | Adds MCP server to ~/.cursor/mcp.json. Restart Cursor to activate. | Yes |
| VS Code | Adds MCP server to VS Code settings.json under mcp.servers | Yes |
| OpenClaw | Installs iKnowhy skill to ~/.openclaw/skills/iknowhy/ - active in every agent session | Yes |
| Claude.ai (web) | Prints connector URL for one-time Project integration (Pro/Max/Team/Enterprise only) | Per project |
Target a specific platform
iknowhy setup --key cwy_your_key --platform claude-desktop
iknowhy setup --key cwy_your_key --platform claude-code
iknowhy setup --key cwy_your_key --platform cursor
iknowhy setup --key cwy_your_key --platform vscode
iknowhy setup --key cwy_your_key --platform claude-ai
iknowhy setup --key cwy_your_key --platform all # default - wires everything detectedVerify connectivity
iknowhy verify --key cwy_your_key_here # sends a test event, confirms it landed
iknowhy status # shows which platforms are detected and wiredClaude.ai - one-time Project setup
Requires Pro, Max, Team, or Enterprise plan. Free plan users: use Claude Code or Claude Desktop instead.
- Go to claude.ai - Projects - select or create a project
- Project Settings - Integrations - Add custom integration
- Integration URL:
https://iknowhy.ai/mcp?key=cwy_your_key
Every conversation in that project auto-logs permanently.
OpenClaw agents
iKnowhy ships an OpenClaw skill that is always active once installed. The skill instructs every agent session to log automatically from message 1 - session start, tool calls, decisions, errors, task complete - all chained causally with no user prompting.
iknowhy setup --key cwy_your_key --platform claude-code
# Also installs ~/.openclaw/skills/iknowhy/SKILL.md automatically if OpenClaw is presentEvent limit behavior
When your plan's event limit is reached, iKnowhy silently drops new events on its side. Your AI tool receives a success response and is never interrupted or errored. The dashboard feed pauses until you upgrade at iknowhy.ai/account.
MCP Server
iKnowhy exposes a remote MCP server compatible with any MCP client supporting Streamable HTTP transport.
https://iknowhy.ai/mcp?key=cwy_your_keyTools
| Tool | Plan | Description |
|---|---|---|
new_session(label) | Any | Start a named causal session. Returns session_id. |
log_event(name, session_id, payload, cause_ids, tags) | Any | Log a causal event. Returns event_id. |
get_sessions(limit) | Pro | List recent sessions with event counts. |
get_chain(event_id) | Pro | Trace the full causal ancestry of any event. |
get_violations(session_id) | Pro | Check for broken causal rules. |
Manual MCP registration
// Claude Code: ~/.claude/mcp.json
// Claude Desktop (Windows): %APPDATA%\Claude\claude_desktop_config.json
// Claude Desktop (Mac): ~/Library/Application Support/Claude/claude_desktop_config.json
// Cursor: ~/.cursor/mcp.json
{
"mcpServers": {
"iknowhy": {
"type": "http",
"url": "https://iknowhy.ai/mcp?key=cwy_your_key"
}
}
}Source detection
iKnowhy automatically detects which platform is sending events based on the request's User-Agent and Origin headers. Claude.ai events appear in their own dashboard panel, separate from OpenAI, Gemini, and direct API events. No configuration required - panels materialize automatically when a source logs its first event.
PyRapide Integration
iKnowhy integrates natively with PyRapide, the causal event-driven architecture library for Python by Shane Morris.
PyRapide implements RAPIDE (Rapid Prototyping for Application Domain-specific Integrated Environments), the causal architecture description language developed at Stanford University by David Luckham. It gives you first-class tools to model, execute, and analyze causal event architectures in Python - with async-native execution, Pydantic events, and a composable pattern algebra.
The PyRapideAdapter bridges PyRapide's local causal computation into iKnowhy's persistent event log,
giving you durable storage, a web dashboard, and API access to every causal chain your PyRapide architecture produces.
Install
pip install iknowhy pyrapide
# or: pip install "iknowhy[pyrapide]"Batch mode - flush a completed Computation
Run your PyRapide architecture, then upload the entire causal computation to iKnowhy in one call. Causal links are preserved.
import asyncio
from pyrapide import Engine
from iknowhy import CausewayClient
from iknowhy.pyrapide import PyRapideAdapter
# ... define your @interface, @module, @architecture ...
async def main():
client = CausewayClient(api_key="cwy_...")
adapter = PyRapideAdapter(client, session_id="my-session")
engine = Engine()
comp = await engine.run(arch, timeout=5.0)
# Upload entire computation - causal DAG preserved
event_ids = await adapter.flush_computation(comp)
print(f"Logged {len(event_ids)} events to iKnowhy")
asyncio.run(main())Streaming mode - real-time via StreamProcessor
Attach iKnowhy to a live StreamProcessor and events appear in your dashboard as they flow through your architecture.
from pyrapide import StreamProcessor, InMemoryEventSource, Event
from iknowhy import CausewayClient
from iknowhy.pyrapide import PyRapideAdapter
async def main():
client = CausewayClient(api_key="cwy_...")
adapter = PyRapideAdapter(client, session_id="live-monitor")
source = InMemoryEventSource("agent")
processor = StreamProcessor()
processor.add_source("agent", source)
# Attach before running - events stream to iKnowhy in real time
adapter.attach_stream(processor)
await source.put(Event(name="tool_call", payload={"tool": "browser"}))
await source.close()
await processor.run()
asyncio.run(main())PyRapideAdapter reference
PyRapideAdapter(client, session_id=None, tags=None)
Create an adapter. All methods are fire-and-forget - logging failures never affect your PyRapide computation.
| Method | Description |
|---|---|
flush_computation(comp, session_id, tags) | Upload a completed Computation in topological order |
attach_stream(processor, session_id, tags) | Hook into a live StreamProcessor for real-time logging |
id_map() | Returns PyRapide event.id -> iKnowhy event_id mapping |
clear() | Reset ID map between separate computations |
Built on PyRapide - iKnowhy's PyRapide integration is powered by Shane Morris's PyRapide library, which brings the Stanford RAPIDE causal architecture model to modern Python. If PyRapide is useful to you, give it a on GitHub.
Event Type Reference
You can use any event name, but these built-in types have special meaning for constraints and chain analysis:
| Event Name | When to Use | Required Cause |
|---|---|---|
user_request | User initiates an action or task | None (root event) |
decision | Agent chooses an action to take | Any (typically user_request) |
tool_call | Agent invokes a tool | Typically decision |
tool_result | Tool returns a response | tool_call (enforced by constraint) |
error | Something went wrong | Any |
error_handling | Recovery or mitigation of an error | error (enforced by constraint) |
external_send | Agent sends data externally (email, API, etc.) | decision (enforced by constraint) |
constraint_check | A policy or guardrail was evaluated | Any |
Rate Limits
| Limit | Free | Pro |
|---|---|---|
| Events per month | 10,000 | 1,000,000 |
| API keys | 1 | 10 |
| Data retention | 7 days | 90 days |
| Event writes | 1,000 / min | 1,000 / min |
| Event reads | 300 / min | 300 / min |
When you exceed your monthly event quota, the API returns 402. Rate limit bursts return 429. No surprise charges - ever.
Error Codes
| Code | Cause | Fix |
|---|---|---|
401 | Missing or invalid API key | Check your Authorization: Bearer cwy_... header |
402 | Monthly event quota exceeded | Upgrade to Pro or wait for quota reset |
422 | Invalid request body (bad field types, missing required fields) | Check the field reference above - name is required, max lengths apply |
429 | Rate limit exceeded (too many requests per minute) | Back off and retry. Writes: 1,000/min, reads: 300/min |