> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.recursiv.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.recursiv.io/_mcp/server.

# Internal Ops Agent Template

## What it is

A starting point for an internal agent that does operational work. It is connected to your tools (Slack, email, your database) and runs on a schedule. Sensitive actions go through a tool-approval gate so a human signs off before the agent sends or writes anything.

Recursiv ships hundreds of data integrations, so the same pattern extends to whatever your ops touch.

## What it includes

| Piece          | What it does                                                         |
| -------------- | -------------------------------------------------------------------- |
| Agent          | A model-agnostic agent (any supported model) in permission tool mode |
| Integrations   | Slack, email, and more connected as agent tools                      |
| Database       | A Postgres database for ops state and logs                           |
| Schedule       | An `r.jobs` cron that runs the agent's routine                       |
| Tool approvals | A human approves or rejects each sensitive tool call before it runs  |

## How to start it

Create the agent and its database, then connect integrations.

```bash
npm install @recursiv/sdk
export RECURSIV_API_KEY=sk_live_...
export RECURSIV_ORG_ID=your-org-id
```

```typescript
import { Recursiv } from '@recursiv/sdk';

const r = new Recursiv();
const ORG_ID = process.env.RECURSIV_ORG_ID!;

// 1. Create the agent in permission mode so tool calls require approval
const { data: agent } = await r.agents.create({
  name: 'Ops Agent',
  username: 'ops_' + Date.now(),
  model: 'anthropic/claude-sonnet-4.6',
  system_prompt: 'You run internal ops. Summarize, draft, and flag. Never act without approval.',
  tool_mode: 'permission',
  organization_id: ORG_ID,
});

// 2. Give it a project and database for ops state
const { data: project } = await r.projects.create({
  name: 'ops-infra',
  organization_id: ORG_ID,
});
await r.databases.ensure({ project_id: project.id, name: 'ops' });
```

## Connect integrations

Connect the providers your ops touch. Browse the catalog with `r.integrations.listApps()` and `r.integrations.getTools(provider)`.

```typescript
const { data: slack } = await r.integrations.connect({
  provider: 'slack',
  organization_id: ORG_ID,
});

// For reliable batch work you can run a tool yourself, no LLM in the loop
const { data: emails } = await r.integrations.executeTool({
  connection_id: slack.connection_id,
  tool: 'GMAIL_FETCH_EMAILS',
  arguments: { query: 'is:unread', max_results: 50 },
});
```

## Run on a schedule

A cron job runs the agent's routine. Its `handler_code` executes in the project sandbox.

```typescript
await r.jobs.create({
  name: 'daily-ops-digest',
  cron: '0 8 * * *', // 8am daily
  project_id: project.id,
  handler_code: `
    const { Recursiv } = require('@recursiv/sdk');
    const r = new Recursiv();
    await r.agents.chat('${agent.id}', {
      message: 'Review overnight Slack and email. Draft a digest and flag anything urgent.',
    });
  `,
});
```

## Approve tool calls

Because the agent is in permission mode, sensitive tool calls wait for a human. Surface pending calls and approve or reject them.

```typescript
const { data: pending } = await r.integrations.listPendingExecutions(conversationId);

for (const exec of pending) {
  if (looksSafe(exec)) {
    await r.integrations.approveExecution(exec.id);
  } else {
    await r.integrations.rejectExecution(exec.id);
  }
}
```

## Key SDK calls

* `r.agents.create({ tool_mode: 'permission', model, system_prompt })` - the gated agent
* `r.databases.ensure({ project_id, name })` - ops state and logs
* `r.integrations.listApps()`, `r.integrations.getTools(provider)`, `r.integrations.connect({ provider, organization_id })` - wire up tools
* `r.integrations.executeTool({ connection_id, tool, arguments })` - run a tool deterministically
* `r.jobs.create({ name, cron, handler_code, project_id })` - the scheduled routine
* `r.integrations.listPendingExecutions(conversationId)`, `approveExecution(id)`, `rejectExecution(id)` - tool approvals

## Next steps

* [Connect Node.js](/integrations/connect/connect-node) to script the agent
* [Quickstart](/guides/start-here/quickstart) for first calls
* [API Reference](/api-reference) for every endpoint