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

# Freeze an AI Agent Session into a Doppels Capability

> Use the doppel-freeze skill in Claude, Cursor, or Codex to capture a working agent session as a replayable YAML Capability and Recipe.

The freeze workflow is built around a simple idea: do real work first, then capture it. You open your agent — Claude, Cursor, Codex, or any other supported tool — and work through the problem the normal way. You deploy, migrate, scrape, transform, whatever needs doing. When you have something that works, you say the freeze phrase and the `doppel-freeze` skill takes over. It reads your session, writes a Capability and Recipe in YAML, validates them with the CLI, and asks for your sign-off. From that point forward, the same operation runs locally for zero tokens, every time.

<Note>
  `doppel freeze` is a **skill** for AI agents — not a CLI subcommand. There is no `doppels freeze` command in the binary. The agent writes the YAML; the CLI validates and runs it.
</Note>

## Step 1: Install the freeze skill

Install the skill once per machine or per project. It registers itself with your agent environment so that any supported agent can pick it up.

```shell theme={null}
npx skills add doppelshq/doppels --skill doppel-freeze
```

This works with all supported agents:

* **Claude**
* **Cursor**
* **Codex**
* **OpenCode**
* **Windsurf**
* **VS Code**

You only need to do this once. After installation, every agent session on that machine has access to the freeze skill.

<Note>
  You also need the `doppels` CLI on your `PATH`. If you haven't installed it yet, see the [installation guide](/installation).
</Note>

## Step 2: Do real work in your agent

Open a session in your agent of choice and work through the task you want to capture. There is nothing special to do at this stage — write code, run commands, call APIs, fix the migration, whatever the job is. The freeze skill will read the session history, so the more concrete and complete the work, the better the resulting Capability.

Good candidates for freezing include:

* Fetching data from an API and writing it to a file
* Running a database migration
* Building and packaging a release artifact
* Rotating credentials or applying configuration changes
* Generating a report from raw data

## Step 3: Say the freeze phrase

When the work is done and you're satisfied with the result, tell your agent to freeze it. Use natural language — something like:

> "doppel freeze — turn what we just did into a Capability"

or

> "doppel freeze this as `hn-top-stories`"

The agent recognizes the `doppel freeze` trigger and activates the skill. You don't need to use an exact incantation; the skill is designed to recognize intent.

## What the freeze skill does

Once triggered, the skill works through a fixed sequence without requiring further prompting from you:

<Steps>
  <Step title="Check for the doppels CLI">
    The skill verifies that `doppels` is available on your `PATH`. If it isn't, it tells you exactly how to install it before proceeding.
  </Step>

  <Step title="Initialize the Space if needed">
    If the current folder doesn't have a `.doppels/` directory yet, the skill runs `doppels spaces init` to create the standard layout: `capabilities/`, `recipes/`, and `.doppels/`.
  </Step>

  <Step title="Identify what to capture">
    The skill asks you to confirm what outcome to capture. Each distinct outcome becomes one Capability. If the session produced multiple separable results, you can freeze them individually.
  </Step>

  <Step title="Write the YAML by hand">
    The agent reads through the session — commands run, files written, inputs received, outputs produced — and writes `capabilities/<name>.yaml` and `recipes/<name>.yaml` directly. There is no code generator or `doppels freeze` command doing this work; the agent is authoring the YAML.
  </Step>

  <Step title="Validate and test">
    The skill loops `doppels validate` and a test `doppels run` until the manifests are clean and the Capability executes correctly. It fixes any schema errors or expression problems it finds.
  </Step>

  <Step title="Ask for your sign-off">
    The skill shows you the full contract — inputs, outputs, steps — and waits for your approval before treating the Capability as done.
  </Step>
</Steps>

## Step 4: Review and commit the YAML

After the skill finishes, you'll have two new files in your project:

* `capabilities/<name>.yaml` — the public contract (inputs and outputs)
* `recipes/<name>.yaml` — how it runs (steps, shell commands, return values)

Open them in your editor and review the diff. Check that the inputs match what you actually provided, that the steps reflect what happened in the session, and that the outputs capture what you care about. Then commit both files to Git like any other source file.

```shell theme={null}
git add capabilities/hn-top-stories.yaml recipes/hn-top-stories.yaml
git commit -m "freeze: hn-top-stories v1.0.0"
```

## Sample frozen YAML

Here is what a frozen Capability and Recipe look like for a Hacker News story fetcher — the kind of task you might build in a single agent session and want to replay indefinitely.

**`capabilities/hn-top-stories.yaml`**

```yaml theme={null}
apiVersion: doppels.so/v1alpha1
kind: Capability

metadata:
  name: hn-top-stories
  version: 1.0.0
  displayName: Fetch Top Hacker News Stories

inputs:
  limit:
    type: integer
    required: false

outputs:
  stories_csv:
    type: artifact
    mediaType: text/csv
  story_count:
    type: integer
```

**`recipes/hn-top-stories.yaml`**

```yaml theme={null}
apiVersion: doppels.so/v1alpha1
kind: Recipe

metadata:
  name: hn-top-stories
  version: 1.0.0

provides: [hn-top-stories]
runtime: shell

requires:
  commands: [curl, python3]

defaults:
  approval: never

steps:
  - id: fetch
    name: Fetch top story IDs
    env:
      LIMIT: "{{ inputs.limit }}"
    run:
      shell: sh
      script: |
        LIMIT="${LIMIT:-10}"
        curl -sf "https://hacker-news.firebaseio.com/v0/topstories.json" \
          | python3 -c "import sys,json; ids=json.load(sys.stdin)[:int('$LIMIT')]; print('\n'.join(map(str,ids)))" \
          > story_ids.txt

  - id: write_csv
    name: Fetch stories and write CSV
    run:
      shell: sh
      script: |
        echo "id,title,score,url" > stories.csv
        while IFS= read -r id; do
          python3 -c "
import urllib.request, json, csv, sys
data = json.loads(urllib.request.urlopen(
  'https://hacker-news.firebaseio.com/v0/item/$id.json').read())
w = csv.writer(sys.stdout)
w.writerow([data.get('id',''), data.get('title',''), data.get('score',''), data.get('url','')])
" >> stories.csv
        done < story_ids.txt
        export STORY_COUNT=$(tail -n +2 stories.csv | wc -l | tr -d ' ')
    produces:
      stories_csv:
        file: stories.csv
      story_count:
        env: STORY_COUNT

returns:
  stories_csv: "{{ steps.write_csv.stories_csv }}"
  story_count: "{{ steps.write_csv.story_count }}"
```

<Tip>
  You can freeze any repeatable operation: data pipelines, API integrations, web scraping, report generation, data transforms, DevOps tasks, and more. If you did it once with an agent and it worked, it's a good candidate for a Capability.
</Tip>
