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 iknowhy

Getting Started

You can be up and running in under a minute. Three steps:

  1. Install the SDK
    pip install iknowhy
  2. 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_....

  3. 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_here

Key types

TypeFormatUse
API Keycwy_...Authenticate SDK calls and direct API requests
Admin KeySet via ADMIN_KEY env varCreate 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

name string Required. Event type name. Max 128 chars. e.g. tool_call, decision.
payload object Optional. Arbitrary JSON data attached to the event. Max 50 keys.
session_id string Optional. Groups events into a session. Max 128 chars.
cause_ids list[string] Optional. IDs of events that caused this one. Max 20 items. This builds the causal graph.
tags object Optional. Key-value metadata for filtering and grouping.

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

ParamTypeDefaultDescription
session_idstring-Filter by session
namestring-Filter by event name
limitint100Max 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

ConstraintRule
tool_call_needs_resultEvery tool_call must have a corresponding tool_result that references it
error_needs_handlingEvery error event must be followed by an error_handling event
external_send_needs_decisionEvery 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_here

Platform coverage

PlatformWhat gets wiredPermanent?
Claude DesktopAdds MCP server to claude_desktop_config.json. Restart Desktop to activate.Yes
Claude CodeWrites ~/.claude/mcp.json + auto-logging rules to ~/.claude/CLAUDE.mdYes
CursorAdds MCP server to ~/.cursor/mcp.json. Restart Cursor to activate.Yes
VS CodeAdds MCP server to VS Code settings.json under mcp.serversYes
OpenClawInstalls iKnowhy skill to ~/.openclaw/skills/iknowhy/ - active in every agent sessionYes
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 detected

Verify connectivity

iknowhy verify --key cwy_your_key_here   # sends a test event, confirms it landed
iknowhy status                            # shows which platforms are detected and wired

Claude.ai - one-time Project setup

Requires Pro, Max, Team, or Enterprise plan. Free plan users: use Claude Code or Claude Desktop instead.

  1. Go to claude.ai - Projects - select or create a project
  2. Project Settings - Integrations - Add custom integration
  3. 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 present

Event 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_key

Tools

ToolPlanDescription
new_session(label)AnyStart a named causal session. Returns session_id.
log_event(name, session_id, payload, cause_ids, tags)AnyLog a causal event. Returns event_id.
get_sessions(limit)ProList recent sessions with event counts.
get_chain(event_id)ProTrace the full causal ancestry of any event.
get_violations(session_id)ProCheck 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.

MethodDescription
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 NameWhen to UseRequired Cause
user_requestUser initiates an action or taskNone (root event)
decisionAgent chooses an action to takeAny (typically user_request)
tool_callAgent invokes a toolTypically decision
tool_resultTool returns a responsetool_call (enforced by constraint)
errorSomething went wrongAny
error_handlingRecovery or mitigation of an errorerror (enforced by constraint)
external_sendAgent sends data externally (email, API, etc.)decision (enforced by constraint)
constraint_checkA policy or guardrail was evaluatedAny

Rate Limits

LimitFreePro
Events per month10,0001,000,000
API keys110
Data retention7 days90 days
Event writes1,000 / min1,000 / min
Event reads300 / min300 / min

When you exceed your monthly event quota, the API returns 402. Rate limit bursts return 429. No surprise charges - ever.

Error Codes

CodeCauseFix
401Missing or invalid API keyCheck your Authorization: Bearer cwy_... header
402Monthly event quota exceededUpgrade to Pro or wait for quota reset
422Invalid request body (bad field types, missing required fields)Check the field reference above - name is required, max lengths apply
429Rate limit exceeded (too many requests per minute)Back off and retry. Writes: 1,000/min, reads: 300/min