---
title: "Install a pack"
description: "A pack is an integration's tools, or a governed workflow, in one file: the secrets it needs, reads, governed writes with read-backs, approval policies installed off, and suggested limits. Install one with the CLI."
---

> A pack that needs a [connected account](/execution/connected-accounts) stops at install and prints the command that connects it.

A pack sets up a workflow that an agent can run under Anlyon's controls. Installing one makes the same API calls you could make by hand: it stores secrets, creates [declared actions](/guides/any-http-api), creates approval policies, and, if you ask, creates [impact limits](/execution/impact-limits). There is no pack endpoint and nothing a pack enforces on its own.

## What a pack guarantees, and what it does not

- **A read changes nothing.** It returns the provider's answer, has no limit and no receipt, and is logged; an approval policy can still match it.
- **Every write is governed.** It declares what it changes, counted against limits. Where the provider can show the change, a read-back that matches grades the receipt `confirmed`; a write with none says why in its description and grades `acknowledged`.
- **Policies install disabled.** You review each one and enable it. A pack cannot install a policy that approves on anyone's behalf.
- **Limits are created only when you ask** (`--with-limits`). Otherwise the install prints them as suggestions.
- **An action can only send a secret to that secret's hosts.** The installer refuses before any call otherwise.
- **A refused install changes nothing.** The installer decides from reads first and writes only when everything checks out.

A declared action has no provider idempotency and no stale-state protection, and a read-back can match a resource that already existed. Each pack's README lists its own limitations, and each action's description carries them into the preview a reviewer sees.

## Ten minutes with `anlyon/outbound-sales`

The outbound-sales pack updates a HubSpot contact, books a Google Calendar meeting and announces the win in a Slack channel. All three sign in, and arrive in later releases, so this walk-through installs once they do.

1. **Install the CLI and log in**

    Installing a pack needs `secrets:read`, `secrets:write`, `actions:read`, `actions:write`, `policies:read` and `policies:write`, and creating limits also needs `impact-limits:write`. Browser login cannot grant the policy and limit scopes, so create an API key with them in the console (Settings → API keys) and log in with it:

    ```bash
    npm install -g @anlyonhq/cli
    anlyon auth login --api-key-stdin < key.txt
    ```

2. **See what it would do**

    ```bash
    git clone https://github.com/AnlyonHQ/anlyon-platform
    anlyon packs plan ./anlyon-platform/packs/outbound-sales
    ```

    Nothing is sent. The plan lists every secret, action, policy and limit, and whether install would create it, skip it or need something from you first.

3. **Connect the accounts it needs**

    ```bash
    anlyon connections add hubspot --secret HUBSPOT
    anlyon connections add google-calendar --secret GOOGLE_CALENDAR
    anlyon connections add slack --secret SLACK
    ```

4. **Install**

    ```bash
    anlyon packs install ./anlyon-platform/packs/outbound-sales --yes
    ```

    The actions are installed as `outbound-sales-update-contact`, `outbound-sales-book-meeting` and `outbound-sales-announce-win`. Installing again changes nothing. If a definition changed, the install refuses unless you pass `--update`, which adds a new action version.

5. **Review and enable the policies**

    ```bash
    anlyon policies list
    ```

    The pack suggests approval for a stage change to `customer`, and for meetings with more than three attendees. They are off until you enable them in the console.

6. **Add the limits**

    ```bash
    anlyon packs install ./anlyon-platform/packs/outbound-sales --with-limits --yes
    ```

## From an SDK

The CLI and the console use the same installer, in the TypeScript SDK:

```typescript
import { readFile } from 'node:fs/promises';
import { Client } from '@anlyonhq/sdk';

const client = new Client({ apiKey: process.env.ANLYON_API_KEY! });
const manifest = JSON.parse(await readFile('packs/outbound-sales/pack.json', 'utf8'));

const plan = await client.packs.plan(manifest);           // nothing sent
const result = await client.packs.install(manifest, { withLimits: true });
console.log(result.disabledPolicies);                     // review, then enable
```

The Python SDK does not have `packs` yet.

### Install some operations, under your own secret name

Each integration has a **catalogue pack** holding its operations (`anlyon/hubspot`, `anlyon/slack`). It is what the console's [operations screen](/execution/connected-accounts#choose-what-your-agent-may-do) installs one switch at a time. From the CLI, pick the operations with `--action`, and map the pack's secret name to yours with `--secret-name`:

```bash
anlyon packs install ./packs/hubspot --yes \
  --action create-company --action add-note \
  --secret-name HUBSPOT=HUBSPOT_SALES
```

Only the secrets, parameters, policies and limits those operations use come with them. `--no-prefix` installs them under their own names. The SDK takes the same options:

```typescript
await client.packs.install(manifest, {
  actions: ['create-company'],
  secretNames: { HUBSPOT: 'HUBSPOT_SALES' },
});
```

A workflow pack reuses a catalogue operation by reference, `{ "name": "note-customer", "ref": "anlyon/hubspot#add-note" }`, so the two never differ. The CLI finds `anlyon/hubspot` in the sibling `hubspot/` directory. From the SDK, pass `resolvePack: (id) => manifestFor(id)`; without it a pack with a reference is refused.

## Parameters and stored secrets

Some packs need values fixed at install, and stored secrets that are not connected accounts. `anlyon/support-refunds` needs a Stripe account, a Slack channel and a Stripe key:

```bash
anlyon packs install ./packs/support-refunds --yes \
  --param stripe_account=acct_123 --param slack_channel=C0123456789 \
  --secret STRIPE_KEY=rk_test_...
```

A stored secret is bound to the pack's hosts and to headers. An existing secret is never overwritten. The CLI never prints a secret value.

## Run every action once

Each integration's pack carries an exercise: one run through all of its actions against your own account, in an order that works, carrying ids from step to step and cleaning up after itself where the provider allows.

```bash
anlyon packs install ./packs/github --yes
anlyon packs exercise ./packs/github --need owner=acme --need repo=sandbox --need base_branch=scratch --need head_branch=try-1 --need reviewer_login=sam
```

`--need` gives the values the run cannot create itself; the pack's README lists them. It asks before it starts, because writes go to the real provider. It stops at the first step that does not succeed and prints, for every step, its outcome, receipt grade and effect id.

## Write your own

A pack is a `pack.json` in the `anlyon-pack/v1` format. The reference, the JSON Schema and the first-party packs are in [`packs/`](https://github.com/AnlyonHQ/anlyon-platform/tree/main/packs) in the Anlyon repository.
