The `ctx` object is available in both `Create` and `Next` hooks. It provides messaging, memory, tracing, tool calls, and agent-to-agent communication.
## Properties
```typescript
ctx.chat_id // Current chat session ID
ctx.assistant_id // This assistant's ID
ctx.locale // User locale, e.g. "en-us"
ctx.route // Request route (URL path + query)
ctx.metadata // Metadata map — set by caller or Create Hook's metadata return
ctx.authorized // Auth info: { user_id, team_id, ... }
ctx.authorized?.user_id // Current user ID
ctx.authorized?.team_id // Current team ID
```
## Messaging
### Send a Message
```typescript
ctx.Send("Hello!"); // text shorthand
ctx.Send({ type: "text", props: { content: "Hello!" } });
ctx.Send({ type: "error", props: { message: "Failed", code: "E001" } });
```
### Streaming
```typescript
const msgId = ctx.SendStream({ type: "text", props: { content: "" } });
ctx.Append(msgId, "Step 1... ");
ctx.Append(msgId, "Step 2... ");
ctx.End(msgId);
```
### Update a Streaming Message
```typescript
const msgId = ctx.SendStream({ type: "loading", props: { message: "Loading..." } });
// ... do work ...
ctx.Replace(msgId, { type: "text", props: { content: "Done!" } });
ctx.End(msgId);
```
### Merge / Set Fields
```typescript
const msgId = ctx.SendStream({ type: "status", props: { progress: 0 } });
ctx.Merge(msgId, { progress: 50 }, "props");
ctx.Merge(msgId, { progress: 100, done: true }, "props");
ctx.End(msgId);
// Set a specific field
ctx.Set(msgId, "success", "props.status");
```
### Group Messages (Block / Thread)
```typescript
const blockId = ctx.BlockID();
ctx.Send("Step 1", blockId);
ctx.Send("Step 2", blockId);
ctx.EndBlock(blockId);
```
## Memory
Four namespaces with different scopes — covered in depth on the [Memory](./memory) page.
| Namespace | Scope | Survives |
|-----------|-------|---------|
| `ctx.memory.context` | This request | Create → Next only |
| `ctx.memory.chat` | This chat session | Until chat ends |
| `ctx.memory.user` | Per user | Indefinitely |
| `ctx.memory.team` | Per team | Indefinitely |
```typescript
ctx.memory.context.Set("key", value);
const v = ctx.memory.context.Get("key");
```
## MCP
Manually call MCP tools from a Hook (as opposed to letting the LLM call them automatically):
```typescript
// Call one tool
const result = ctx.mcp.CallTool("server-id", "tool-name", { arg: "value" });
// Call multiple tools on the same server — sequentially
const results = ctx.mcp.CallTools("server-id", [
{ name: "tool1", arguments: { a: 1 } },
{ name: "tool2", arguments: { b: 2 } },
]);
// Call multiple tools on the same server — in parallel
const results = ctx.mcp.CallToolsParallel("server-id", [
{ name: "tool1", arguments: { a: 1 } },
{ name: "tool2", arguments: { b: 2 } },
]);
// Cross-server parallel calls — waits for all to complete
const results = ctx.mcp.All([
{ mcp: "server1", tool: "search", arguments: { q: "query" } },
{ mcp: "server2", tool: "fetch", arguments: { id: 1 } },
]);
// Cross-server — first success wins
const result = ctx.mcp.Any([...]);
// Cross-server — first to complete wins (regardless of success/error)
const result = ctx.mcp.Race([...]);
```
## Search
Trigger search from a Hook:
```typescript
const web = ctx.search.Web("query", { limit: 10 });
const kb = ctx.search.KB("query", { collections: ["docs"], threshold: 0.7 });
const db = ctx.search.DB("query", { models: ["model.name"] });
// Parallel — waits for all to complete
const results = ctx.search.All([
{ type: "web", query: "topic" },
{ type: "kb", query: "topic", collections: ["docs"] },
]);
// First success wins
const result = ctx.search.Any([...]);
// First to complete wins (regardless of success/error)
const result = ctx.search.Race([...]);
```
## Agent (A2A)
Call another agent as a function. The called agent runs in an **independent context** — it does not share conversation history.
```typescript
// Basic call
const result = ctx.agent.Call("assistant-id", messages);
// With streaming callback
const result = ctx.agent.Call("assistant-id", messages, {
onChunk: (msg) => {
ctx.Send(msg); // Forward chunks to client
return 0; // 0 = continue
},
});
// Parallel calls — waits for all to complete
const results = ctx.agent.All([
{ agent: "agent-1", messages, options: {} },
{ agent: "agent-2", messages },
]);
// First success wins
const result = ctx.agent.Any([...]);
// First to complete wins
const result = ctx.agent.Race([...]);
```
For shared-history routing, use `delegate` in the Hook return value — covered in [Multi-Agent](./multi-agent).
## LLM
Call an LLM directly without going through the agent pipeline. All methods are streaming — use the `onChunk` callback to receive output:
```typescript
// Single connector
const result = ctx.llm.Stream("gpt-4o", messages, {
onChunk: (msg) => {
ctx.Send(msg); // forward to client
return 0; // 0 = continue, non-zero = stop
},
});
// Multiple connectors in parallel — waits for all to complete
const results = ctx.llm.All([
{ connector: "gpt-4o", messages, options: { temperature: 0.5 } },
{ connector: "claude-3", messages },
]);
// Multiple connectors — first success wins
const result = ctx.llm.Any([...]);
// Multiple connectors — first to complete wins (regardless of success/error)
const result = ctx.llm.Race([...]);
```
## Trace
Record debug nodes visible in the agent trace view:
```typescript
const node = ctx.trace.Add(
{ input: "data" },
{ label: "Processing", description: "Parsing user input" }
);
node.Info("Step started");
node.SetOutput({ result: data });
node.Complete({ status: "done" });
// or node.Fail("Error message");
// Top-level logging (no node)
ctx.trace.Info("Starting...");
ctx.trace.Error("Something went wrong");
```
## Sandbox (CLI Agent)
Available only when `sandbox` is configured — covered in the CLI Agent chapter.
```typescript
ctx.sandbox.ReadFile("output.json");
ctx.sandbox.WriteFile("input.txt", content);
ctx.sandbox.Exec(["npm", "test"]);
```
For file-system access via `ctx.workspace` and container operations via `ctx.computer`, see the [Workspace API](/tutorials/agent/cli-agent/workspace) page.
## What's Next
Memory is used heavily in real agents — it deserves its own page.
→ **[Memory](./memory)**