> ## Documentation Index
> Fetch the complete documentation index at: https://docs.checkfu.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Base URL: https://api.checkfu.com. Current wire version: `2026-08-31` (`Checkfu-Version: 2026-08-31`).
> Mutating HTTP requests require `Authorization: Bearer $CHECKFU_API_KEY`, `Checkfu-Version: 2026-08-31`, `Content-Type: application/json`, and `Idempotency-Key` on retriable writes. Ordinary API keys are Workspace-bound; do not send a Workspace selector header.
> Core workflow: create an Agent (`POST /v1/agents`) and Environment (`POST /v1/environments`), grant `use_environment` (`POST /v1/permission-assignments`), create a Session (`POST /v1/sessions`), send events (`POST /v1/sessions/{id}/events`), stream progress (`GET /v1/sessions/{id}/events/stream`), and read the input result (`GET /v1/sessions/{id}/inputs/{input_id}/result`).
> Domain model: an Agent is mutable configuration; a Session freezes its AgentVersion and Environment at creation and owns its private workspace and ordered event history. Vault stores secret credentials; Connection links an external account; ActionApproval records human approval before an action runs.
> Capability status combines `audience`, `stability`, `availability`, evaluated prerequisites, and release evidence; check https://docs.checkfu.com/getting-started/status (`GET /v1/support/capabilities`) for live `available` status.

# Build a personal assistant

> Run an Agent as one person, keep its Session private to them, and ask them before anything leaves it.

A personal assistant is an [Agent](https://docs.checkfu.com/concepts/agents.md) that works as one person, with that person's connected accounts. Its [Session](https://docs.checkfu.com/concepts/sessions-and-runs.md) is visible only to them, and any write that leaves it waits for their approval.

This guide creates the Session from your backend with an API key that acts as the person, and names a `personal` audience so the boundary rules apply. Agent access setup writes the Session's grants for you.

Before starting, have:

* A Workspace-bound `CHECKFU_API_KEY` that can administer grants (root or admin) for the one-time setup.
* The person's Principal (`prin_…`) in `CHECKFU_PRINCIPAL_ID`.
* An Agent (`agent_…`) and its current version, using a [Connection](https://docs.checkfu.com/guides/connect-a-providers-account.md) the person connected.
* An Environment (`env_…`) with no network access. A personal Session refuses an Environment that allows any host.

> [!WARNING]
>
> Plain HTTP against the Checkfu API needs no private package.
> The Checkfu CLI and TypeScript SDK are optional private-alpha artifacts; the HTTP requests work without them.
> Part of this flow is behind a rollout fence; a deployment that has not enabled it refuses the request rather than running it.
> Confirm [capability status](https://docs.checkfu.com/getting-started/status.md) before making availability part of your application's contract.

## 1. Set up access once

Agent access setup grants the person `act_as` on the Agent, and the Agent its Environment and harness. It works on the exact Agent version you name, which must be the current one. The examples use the [TypeScript SDK](https://docs.checkfu.com/reference/typescript-sdk.md):

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { Checkfu } from "@checkfu/sdk"

const checkfu = new Checkfu({ apiKey: process.env.CHECKFU_API_KEY! })

const setup = await checkfu.connectionAssignments.setupAgentAccess(
  agentId,
  {
    agent_version: currentVersion,
    acted_as: personId,
    environment_id: environmentId,
    workflow: "acted_as",
  },
  undefined,
  { idempotencyKey: `assistant-setup-${personId}-${currentVersion}` },
)
```

Pass `{ dry_run: "true" }` as the third argument to see which grants are `present`, `missing` or `blocked` without writing any. A `blocked` grant is refused by an ActionPolicy or is outside its time window; fix it before applying. Run setup again after a new Agent version; grants that already exist report `present`.

## 2. Create a personal Session

Name the person in `acted_as` and set `audience` to `personal`:

```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request POST https://api.checkfu.com/v1/sessions \
  --header "Authorization: Bearer $CHECKFU_API_KEY" \
  --header "Checkfu-Version: 2026-08-31" \
  --header "Idempotency-Key: assistant-session-001" \
  --header "Content-Type: application/json" \
  --data '{
    "agent": { "type": "agent", "id": "agent_0123456789abcdef0123456789abcdef", "version": 3 },
    "environment_id": "env_0123456789abcdef0123456789abcdef",
    "acted_as": "prin_0123456789abcdef0123456789abcdef",
    "audience": { "type": "personal" }
  }'
```

```ts TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
const session = await checkfu.sessions.create(
  {
    agent: { type: "agent", id: agentId, version: currentVersion },
    environment_id: environmentId,
    acted_as: personId,
    audience: { type: "personal" },
  },
  { idempotencyKey: `assistant-session-${requestId}` },
)

await checkfu.sessions.events.send(
  session.id,
  {
    events: [
      {
        type: "user.message",
        content: [{ type: "text", text: "Summarize my unread support tickets and draft replies." }],
      },
    ],
  },
  { idempotencyKey: `assistant-message-${requestId}` },
)
```

Name the audience explicitly. A Session that names neither `audience` nor `scope` is still private to the person, but it gets none of the boundary rules below: allowed writes run without asking. The `checkfu.launch` helper cannot set an audience yet, so create the Session directly.

To narrow what the assistant can do, add a [`scope`](https://docs.checkfu.com/concepts/sessions-and-runs#audience-and-scope). For example, keep only the Connection tools that read and draft, or cap a refund amount.

A personal Session cannot hold sandbox network access, so creation answers `policy.denied` if the Environment allows any host. A FileTree mount that declares Git `writeback` is refused with `validation.malformed`. Built-in `web_fetch` and `web_search` stay only on the `claude-code` platform harness, where they ask before every call. Custom tools stay, and each call asks the person first.

## 3. Ask the person before a write leaves

When the assistant calls a Connection tool that writes, such as sending an email or updating a ticket, or calls a custom tool, the Run pauses on `run.requires_action` with an `action_approval`. This happens on every call, even when an ActionPolicy allows the tool or a StandingApproval matches it. Calls that only read do not pause.

Only the person the Session acts as can approve. Show them the frozen action (see [Handle an approval](https://docs.checkfu.com/guides/handle-an-approval.md)), then record their decision with `acted_as` set to them:

```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request POST \
  "https://api.checkfu.com/v1/action-approvals/$APPROVAL_ID/responses" \
  --header "Authorization: Bearer $CHECKFU_API_KEY" \
  --header "Checkfu-Version: 2026-08-31" \
  --header "Idempotency-Key: approval-$APPROVAL_ID" \
  --header "Content-Type: application/json" \
  --data '{
    "expected_version": 1,
    "decision": "approve",
    "acted_as": "prin_0123456789abcdef0123456789abcdef"
  }'
```

```ts TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
await checkfu.actionApprovals.decide(
  approvalId,
  { expected_version: approval.version, decision: "approve", acted_as: personId },
  { idempotencyKey: `approval-${approvalId}` },
)
```

The person needs `approve` on the Connection, or on the Agent for a custom tool. A response from another person, a service, or an API key acting as itself is refused. The person can also answer in the Console. Once the write is approved, the destination's own permissions and retention apply to what was written.

## What this leaves out

* The person reading their own Session with their own Principal credential instead of your API key.
* Sharing with a team. A Session that acts as a person can only be `personal`. A `group` Session is created by a root or admin key acting as itself.
* Background work on a schedule. That is an [Automation](https://docs.checkfu.com/concepts/automations.md), which needs the person's consent and current access when it runs.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.