v1.0

SDKs & Tools

The SDKs are optional. The proxy works without them: just change your base URL (see Quickstart). Use the SDKs when you want deeper, more detailed recording of your agent's internal steps.

Proxy vs SDK: what's the difference?
  • Proxy (easiest): Records every AI request and response automatically. You change one URL and you're done. Great for seeing what your agent sends to the AI and what it gets back.
  • SDK (more detail): Records the agent's internal steps too: its reasoning, tool calls, context, and decision-making. Use this when you need to understand why the agent did something, not just what it sent to the AI.

Quick Start

Install the SDK, add two lines to the file where your agent starts up, and you're done. You'll need an Arkna API key: get one from Settings → API Keys in the dashboard.

Run this in your terminal to install:

pip install arkna

Then add these two lines to the top of your agent's main file (e.g., main.py or app.py):

import arkna
arkna.init("ark_live_your_key_here", agent_name="my-agent")

Run this in your terminal to install:

npm install arkna

Then add these two lines to the top of your agent's main file (e.g., index.ts or app.js):

import { init } from 'arkna';
init({ apiKey: 'ark_live_your_key_here', agentName: 'my-agent' });
That's the whole integration. Auto-instrumentation captures runs, steps, and tool calls. Read on only if you need manual, fine-grained control.

Configuration

The SDK can be configured two ways:

Option 1: Pass values directly (simplest)

from arkna import ArknaClient

client = ArknaClient(
    token="ark_live_your_key_here",
    agent_name="my-agent",
    base_url="https://api.arkna.com.au/api/v1"
)
import { ArknaClient } from 'arkna';

const client = new ArknaClient({
  token: 'ark_live_your_key_here',
  agentName: 'my-agent',
  baseUrl: 'https://api.arkna.com.au/api/v1'
});

Option 2: Use environment variables

Set these in your .env file or your system environment. An environment variable is a named setting that your program can read. It lets you keep secrets out of your code.

# Add these to your .env file (in your project's root folder)
ARKNA_API_KEY=ark_live_your_key_here
ARKNA_AGENT_NAME=my-agent

Then create the client without any arguments: it reads from the environment automatically:

from arkna import ArknaClient
client = ArknaClient()  # reads from environment variables
import { ArknaClient } from 'arkna';
const client = new ArknaClient();  // reads from environment variables

Manual Instrumentation

For full control over what gets recorded and when, use the client methods directly. This lets you record individual steps, tool calls, and context snapshots inside your agent's logic.

startRun()

Start recording a new agent run. Returns a run object with a run_id you'll use for all subsequent calls.

run = client.start_run(
    trigger_type="api",        # what started this run: api, schedule, webhook, manual, auto
    input="Summarize Q4 sales",
    session_id=session["session_id"]  # optional — group with other runs
)
print(run["run_id"])
const run = await client.startRun({
  triggerType: 'api',          // what started this run: api, schedule, webhook, manual, auto
  input: 'Summarize Q4 sales',
  sessionId: session.sessionId  // optional — group with other runs
});
console.log(run.runId);

recordStep()

Record a single step within a run. Steps are automatically hash-chained for tamper-proof integrity.

step = client.record_step(run["run_id"],
    step_type="reasoning",     # reasoning, tool_call, retrieval, action, error, completion
    input="What data do I need?",
    output="I should query the sales database",
    tokens_used=150
)
const step = await client.recordStep(run.runId, {
  stepType: 'reasoning',       // reasoning, tool_call, retrieval, action, error, completion
  input: 'What data do I need?',
  output: 'I should query the sales database',
  tokensUsed: 150
});

recordToolCall()

Record when your agent uses an external tool (API, database, file system, etc.).

tool = client.record_tool_call(run["run_id"],
    tool_name="query_database",
    arguments={"query": "SELECT * FROM sales WHERE q='Q4'"},
    result={"rows": 142},
    status="success",          # success, error, or timeout
    duration_ms=230,
    target_system="postgresql"
)
const tool = await client.recordToolCall(run.runId, {
  toolName: 'query_database',
  arguments: { query: "SELECT * FROM sales WHERE q='Q4'" },
  result: { rows: 142 },
  status: 'success',           // success, error, or timeout
  durationMs: 230,
  targetSystem: 'postgresql'
});

captureContext()

Snapshot what the agent knew at a specific point. This powers the "what did the agent know?" panel in replay.

ctx = client.capture_context(run["run_id"],
    system_prompt="You are a sales analyst...",
    active_instructions=["Use Q4 data only"],
    retrieved_documents=[{"title": "Q4 Report", "source": "s3://..."}],
    total_tokens=2048
)
const ctx = await client.captureContext(run.runId, {
  systemPrompt: 'You are a sales analyst...',
  activeInstructions: ['Use Q4 data only'],
  retrievedDocuments: [{ title: 'Q4 Report', source: 's3://...' }],
  totalTokens: 2048
});

completeRun()

Complete a run with a final status. This triggers hash chain computation and anomaly detection.

result = client.complete_run(run["run_id"],
    status="completed",        # completed, failed, or timeout
    output="Q4 sales: $1.2M across 142 transactions",
    total_tokens=3500,
    total_cost_cents=42
)
print(f"Chain hash: {result['chain_hash']}")
const result = await client.completeRun(run.runId, {
  status: 'completed',         // completed, failed, or timeout
  output: 'Q4 sales: $1.2M across 142 transactions',
  totalTokens: 3500,
  totalCostCents: 42
});
console.log(`Chain hash: ${result.chainHash}`);

trace() · All-In-One Wrapper

The trace() method is a shortcut that wraps the entire run lifecycle. It starts a run, calls your function, and auto-completes the run when your function finishes (even if it throws an error).

async def my_agent_logic(run):
    await run.step(step_type="reasoning", output="Thinking...")
    await run.tool(tool_name="search", status="success", result={"hits": 5})
    await run.step(step_type="completion", output="Done!")
    return "Final result"

result = await client.trace("summarize-q4", my_agent_logic)
const result = await client.trace('summarize-q4', async (run) => {
  await run.step({ stepType: 'reasoning', output: 'Thinking...' });
  await run.tool({ toolName: 'search', status: 'success', result: { hits: 5 } });
  await run.step({ stepType: 'completion', output: 'Done!' });
  return 'Final result';
});
Errors are handled automatically. If your function throws an error, trace() records it as a failed run with the error details. You don't need to handle completeRun() yourself.

Method Reference

MethodPython NameDescription
createSession()create_session()Create a session to group related runs
closeSession()close_session()Close a session
startRun()start_run()Start recording a new agent run
recordStep()record_step()Record a step within a run
recordStepBatch()N/ARecord multiple steps at once (Node.js only)
recordToolCall()record_tool_call()Record an external tool call
captureContext()capture_context()Snapshot the agent's context
completeRun()complete_run()Complete a run with hash chain
trace()trace()Wrap full run lifecycle in one call
Naming convention: The Node.js SDK uses camelCase (e.g., startRun, stepType). The Python SDK uses snake_case (e.g., start_run, step_type). Both talk to the same API.