# Running an unattended job you operate with a CoreSpeed agent key (/blog/an-unattended-job-with-an-agent-key)

![Illustration: A small friendly robot with a round camera-eye head works alone at night under a single desk lamp, a wall clock showing three, with a name badge on its chest and a coin jar on the desk.](/blog/an-unattended-job-with-an-agent-key/hero.webp)

An unattended job is a process you run on your own schedule, on your own machine or server, with nobody watching it. CoreSpeed does not run the job. What CoreSpeed gives it is an identity of its own, an agent key, a monthly spend cap, a route to a person when a write needs approval, and an activity trail.

**You run the job, the org scopes it**

* Your server: cron starts the nightly job at 03:00 with an `sk-csa-` agent key
* CoreSpeed: an agent of its own that its owner answers for, a monthly cap set on the key in credits, an activity trail with the agent as the actor
* Reaches: shared Slack and shared Notion; a Gmail connection private to a member, never
* A write the policy names: `slack__post_message` to a public channel is held, the job waits with `manage__approval_wait`, and the card goes to the agent's owner

## Why not reuse your own API key? \[#why-not-reuse-your-own-api-key]

An `sk-cs-` member key acts as you. Every call it makes reaches your private connections and the organization's shared ones, and every record in the activity trail carries your name. For a job that runs at 3 a.m. without you, that is the wrong shape. If the job misbehaves, the trail says you did it. If the job reads a page that carries injected instructions, it can act through your personal accounts.

An agent principal fixes both problems. It has an id of its own, it reaches the organization's shared connections only, and it never sees a member's private connections. A member creates it and becomes its owner. Ownership is accountability: the owner answers for the agent and, with org admins, may manage it. The agent inherits neither the owner's connections nor the owner's role. The full model is on the [authentication page](/docs/authentication).

## How do you create the agent and its key? \[#how-do-you-create-the-agent-and-its-key]

Any member can create an agent in Dashboard → Settings or with `manage__agents_create` from a signed-in client. The owner or an org admin then mints an `sk-csa-` key with `manage__agents_key_create` or from the dashboard. Set a monthly spend cap in credits on the key while you are there. Keys are per environment, so a production key is rejected on staging.

Keep the key out of config files. Read it from an environment variable such as `CORESPEED_API_KEY` and inject it into the client's header at start time. The entry your client needs is the usual one, with a header:

```json
{
  "mcpServers": {
    "corespeed": {
      "type": "http",
      "url": "https://api.corespeed.io/mcp",
      "headers": { "Authorization": "Bearer sk-csa-..." }
    }
  }
}
```

Your scheduler, whether cron, a systemd timer or a CI runner, starts the agent process with that environment and the agent signs in as itself.

## What can the job reach? \[#what-can-the-job-reach]

| Surface                                                                | With an `sk-csa-` agent key                          |
| ---------------------------------------------------------------------- | ---------------------------------------------------- |
| Shared connections (Slack workspace bot, shared Notion, shared GitHub) | Reachable                                            |
| A member's private connections                                         | Never                                                |
| Built-ins: memory, media, web, social                                  | Reachable, under the agent's own capability settings |
| `manage__remote_list`                                                  | Runs                                                 |
| `manage__keys_*`, `manage__agents_*`, `manage__whoami`                 | Listed, refused with `jwt_session_required`          |
| Metered calls past the key's monthly cap                               | Refused with `key_spend_limit_exceeded`              |

The last two rows matter for job design. An unattended job cannot mint keys or create more agents; those tools need a member session. And once the cap is reached, metered calls stop until the month rolls over or an admin raises the cap. Caps are checked at the request boundary, so one action already in flight can finish above the remaining amount.

## What happens when the policy says Ask? \[#what-happens-when-the-policy-says-ask]

If your organization has Smart Approval on, every write the job makes through CoreSpeed is judged against the policy. Reads are never gated. A write the policy names comes back at once with a receipt: approval required, not run, call `manage__approval_wait` with this id. The job should call `approval_wait` and block. A card goes to the people who can decide: the owner of the agent, in the dashboard queue, by email, or in Slack if an admin installed the CoreSpeed bot. The agent cannot approve its own action.

Two timers shape the job. The card expires about thirty seconds after the agent stops waiting, and a card nobody decides expires after an hour. So an unattended job has two sane designs: wait for the decision, or treat the hold as a result, log it, and move on. Do not re-send the call. A fresh `tools/call` is a new request and can raise a second card. The rest of the flow is on the [approvals page](/docs/approvals).

## How do you stop it, and how do you read what it did? \[#how-do-you-stop-it-and-how-do-you-read-what-it-did]

Suspend the agent when you want it quiet. Every request then answers `403 agent_suspended`; the keys stay intact, so do not rotate them. Retire the agent when it is done for good: the record survives for attribution and its keys answer `401 invalid_api_key`.

Every call the job makes lands in Dashboard → Activity with the agent as the actor. Members see their own actions; org admins see the organization. Each record names the tool, the outcome (`ok`, `error`, `held`, `denied`) and, when a charge exists, the charge the ledger recorded. Cost per run is readable there without any instrumentation of your own, as described on the [activity page](/docs/activity) and the [billing page](/docs/billing).

## FAQ \[#faq]

**Does CoreSpeed run the job?** No. You run it on your machine, your server or your CI. CoreSpeed equips the agent that process starts.

**Can the job use my Gmail?** Only if that connection is shared with the organization. An agent key never reaches a member's private connections.

**What if the key leaks?** Revoke or rotate the key, or suspend the agent. The spend cap bounds what a leaked key can cost in the meantime.

**Can the job create its own keys?** No. `manage__keys_*` and `manage__agents_*` run only under a member session.