# Introduction

Stoobly is an API mock framework with seamless CI setup that enables end-to-end (E2E) testing.

## Why use Stoobly?

⚡ **Easily create realistic API mocks** by recording HTTP(S) requests.

💡 Maintaining mocks gets expensive. **Streamline maintenance** with stale mock detection and automated regeneration.

🔨 **Minimize regressions** of customer workflows with fast and reliable E2E tests.

🚀 Supercharge CI setup with ready-to-go tooling. **Reduce CI setup time** from two weeks to one day.

## **Why do E2E Testing?**

Stoobly enables E2E testing. But before we talk about how, let us first answer what benefits E2E testing provides when compared to other forms of testing:

✅ Validates Real-World Scenarios

✅ Detects Integration Issues

✅ Provides High Code-Coverage

While full of benefits, E2E testing has several drawbacks:

* Dependence on live services make them flaky and slow
* Requires significant tooling support (test runner, mock framework, and CI setup)

## Stoobly Enables E2E Testing

{% hint style="info" %}
The goal of E2E testing is to ensure that real-world scenarios behave as expected. In order to achieve this goal, E2E tests have to be fast, reliable, and running as part of CI.
{% endhint %}

### API Mock Framework

> **Leverage a complete solution for API mocking.**

By serving as an API mock framework, Stoobly makes testing fast and reliable. Stoobly provides the following solutions to problems universal to mocking:

<table><thead><tr><th width="301">Problem</th><th>Solution</th></tr></thead><tbody><tr><td>Creating</td><td>Manual and recording</td></tr><tr><td>Stale Detection</td><td>Contract testing</td></tr><tr><td>Updating</td><td>Manual and automated mock regeneration</td></tr><tr><td>Grouping</td><td>Scenarios</td></tr><tr><td>Response Matching</td><td>Pattern and contract based configurations</td></tr><tr><td>Sharing</td><td>Git commitable mock storage format</td></tr></tbody></table>

### Out-of-the-Box CI Setup

> **Drastically reduce CI setup time. Minimize maintenance.**

Stoobly also empowers users to scaffold tooling to overcome the barrier between running E2E tests locally and running them in CI. Stoobly provides the following solutions to problems universal to CI setup:

<table><thead><tr><th width="300">Problem</th><th>Solution</th></tr></thead><tbody><tr><td>Separate mocks that belong to different services</td><td>Service definitions</td></tr><tr><td>Separate development, testing and CI configurations</td><td>Workflow definitions</td></tr><tr><td>Creating configurations</td><td>Generated Docker compose files</td></tr><tr><td>Updating configurations</td><td>Minimal parameters and centralized resource definitions</td></tr></tbody></table>

## Ready to get Started?

{% content-ref url="/pages/-Mar1-Gka-Tff3z\_01mG" %}
[Installing the Agent](/getting-started/installing-the-agent)
{% endcontent-ref %}

## Looking to Learn More?


# Use Cases


# Generate Mock APIs

## Why Mock APIs?

{% hint style="info" %}
Mocking out APIs results in faster and more reliable tests.
{% endhint %}

Tests that make requests to upstream APIs can suffer from intermittent failures due to updates or downtime. Because upstream APIs can also call other APIs, depending on live services tend to make tests slow. Having flaky and slow tests means more time is spent debugging and less time spent on core features.

## Current State of API Mocking

Below we highlight two types of mock API's and provide examples for each:

* Language specific libraries such as [Mockito](https://github.com/wiremock/wiremock) and [rspec-mocks](https://github.com/rspec/rspec-mocks)
* External mock servers such as [Wiremock](https://github.com/wiremock/wiremock) and [MirageJS](https://github.com/miragejs/miragejs)

In the following two sections, we list challenges with creating and maintaining API mocks. We then summarize how the challengs can be solved by using existing solutions.

### Creating

Creating the initial API mocks is an upfront time cost by Software Engineers and QA Engineer&#x73;**.**

The following lists challenges with creating API mocks and highlights existing solutions:

<details>

<summary>Creating realistic response stubs</summary>

Existing solutions:

* Hard-coding responses
* Use of faker libraries

</details>

<details>

<summary>Precisely matching requests with responses</summary>

Existing solutions:

* Using strict or pattern-based URL matching to map requests to responses
* Headers and bodies are not taken into account

</details>

### **Maintaining**

Maintenance is a variable time cost by Software Engineers and QA Engineers. Every time the request or response contract changes, mocks have to be modified. This becomes a time-consuming process as more and more API endpoints are added. Time spent maintaining scales exponentially with the number of request variations.

The following lists challenges with maintaining mocks and highlights existing solutions:

1. Determining which requests and responses need updating
   * Work with service maintainers
   * Audit change logs of upstream API changes
   * Wait for tests that depend on an out-of-date response to fail
2. Updating mock request variations with up-to-date parameters and/or responses
   * Manually copy/paste or edit the request and/or response

## How Stoobly Helps

{% hint style="info" %}
A mock API works great from the time it is created to when it comes time for maintenance.
{% endhint %}

In order to generate mock APIs, we want to ensure that:

* Request responses can be recorded instead of hard-coding
* Precisely matching requests with responses

In order to maintain mock APIs, we want to ensure that:

* Request responses can be refreshed without having to manually update each one

### Creating Realistic Mocks

{% hint style="success" %}
Stoobly makes creating realistic mocks fast and accessing them precise.
{% endhint %}

#### Recording

Stoobly lets you easily [create mock APIs](/guides/how-to-mock-apis/how-to-enable-mocking) by recording HTTP traffic. To record traffic, Stoobly acts as a proxy between a client and server and intercepts traffic that passes through.

In comparison, to generate HTTP request mocks without recording:

{% stepper %}
{% step %}
Use a client driver (e.g. curl, browser) to send a HTTP request
{% endstep %}

{% step %}
Copy and paste the HTTP response into a mock tool or library
{% endstep %}

{% step %}
Repeat for different request variations and/or endpoints
{% endstep %}
{% endstepper %}

We can see that this process quickly becomes difficult to scale. As either the number of HTTP request variations increase or as new endpoints are added, we have to keep manually adding responses to our mocks.

With recording, the process looks like:

1. Configure a client driver (e.g. curl, browser) to proxy requests to Stoobly
2. Send a HTTP request and let Stoobly record it for you
3. Repeat for as many HTTP requests as you want
4. (Optional) Stoobly enables [configuration of which requests gets recorded](/core-concepts/agent/proxy-settings/filter-rules) and [enables rewriting parts of a request](/core-concepts/agent/proxy-settings/rewrite-rules).
   1. e.g. rewriting any part of the request to filter sensitive data

#### Mocking

Stoobly comes out of the box with comprehensive request and response matching that should cover most use-cases without explicitly stating the match requirements. By default, Stoobly matches an HTTP request using the request method and path only. If you need to include query parameters, body fields, headers, or other components, add a match rule to opt them in.

In comparison, to configure how HTTP requests are matched when mocking manually:

1. Specify a exact path to match or use regex for pattern matching
2. Repeat for every HTTP request that the mock API needs to support

An additional difficultly to highlight here is that matching bodies is often not possible. This is because the body would first have to be pared based on the specified content type.

With Stoobly mocking, the process looks like:

1. Requests will be matched without additional configuration
2. (Optional) Stoobly enables [configuring how a request gets matched](/core-concepts/agent/proxy-settings/match-rules). Matching against query params, body or headers can be either relaxed or tightened.
   1. e.g. Matching based on specific query params and/or ignore headers

### Scaling Maintenance

{% hint style="success" %}
Stoobly helps minimize the impact of having to maintain mocks.
{% endhint %}

We empower you with the ability to [replay recorded requests](/guides/how-to-replay-requests) and either overwrite the existing request response or alternatively, create a new version of the request. The following lists challenges with maintaining mocks and highlights manually:

1. Determining which requests and responses need updating
   * Shared maintenance, updates by producer can immediately be accessed by consumers
2. Updating mock request variations with up-to-date parameters and/or responses
   * Support replaying requests and recording the responses
   * Group a sequence of requests into scenarios and batch replay and record

#### Without Stoobly

The process to update a HTTP response mock manually will look similar to:

1. Determine which mocks need updating
2. Use a client driver to resend a HTTP request
3. Copy and paste the updated response
4. Repeat for other mocks that need updating

While to above flow may not mirror exactly how mocks are always updated (sometimes we directly modify the mock), it serves to illustrates the difficutly in:

1. Understanding which mocks need updating
2. Understanding what a new correct version of the mock looks like

This problem gets even worse when we want to update a sequence of requests that have a relationship with each other (e.g. creating, reading, and deleting a resource are connected by the resource ID).

#### With Stoobly

The process can look similar to:

1. Determine which requests or scenarios need updating
2. Replay and record the requests or scenarios

## Getting Started

### Create Mocks

{% content-ref url="/pages/XRMveeqrNM5K07qs5H8k" %}
[How to Record Requests](/guides/how-to-record-requests)
{% endcontent-ref %}

{% content-ref url="/pages/L80ROjPjA3paJPSgdFzA" %}
[How to Customize Recordings](/guides/how-to-record-requests/how-to-customize-recordings)
{% endcontent-ref %}

### Organize Mocks

{% content-ref url="/pages/Ip67YLrIJPaMa2nYPcu9" %}
[How to Create Scenarios](/guides/how-to-record-requests/how-to-create-scenarios)
{% endcontent-ref %}

### Update Mocks

{% content-ref url="/pages/4AvtwJG25WXsYLe37TDH" %}
[How to Update Requests](/guides/how-to-update-requests)
{% endcontent-ref %}

{% content-ref url="/pages/WGDfUf8LR718Ltv79uSX" %}
[How to Update Scenarios](/guides/how-to-update-requests/how-to-update-scenarios)
{% endcontent-ref %}

### Sharing Mocks

{% content-ref url="/pages/Tyk5SmKa5es0I3YjLQA0" %}
[How to Snapshot Requests](/guides/how-to-mock-apis/how-to-snapshot-requests)
{% endcontent-ref %}


# Empower Development

In order to empower development, we want to:

* Easily re-create application state
* Reduce environment instability

## Recreating Application State

Working on a feature or fixing a bug often depends on triggering a sequence of requests to drive your application to a certain state. For example, when working on a new API to create a resource, we find ourselves:

1. Sending a POST request to create the resource
2. Sending a GET request to confirm the resource was created
3. Sending a DELETE request to reset the system state

With Stoobly, we can record these requests into a scenario. With scenarios, we can:

1. Replay them to retrigger the same sequence of requests
2. Share them with teammates so they replicate the same results

For example given the following imaginary endpoints:

## Create a todo item

<mark style="color:green;">`POST`</mark> `http://localhost:3000/todos`

#### Request Body

| Name                                    | Type   | Description |
| --------------------------------------- | ------ | ----------- |
| description                             | String |             |
| title<mark style="color:red;">\*</mark> | String |             |

{% tabs %}
{% tab title="200: OK " %}

```json
{
    description: '',
    id: 1,
    title: '',
}
```

{% endtab %}
{% endtabs %}

## Describe a todo item

<mark style="color:blue;">`GET`</mark> `http://localhost:3000/todos/:todoID`

{% tabs %}
{% tab title="200: OK " %}

```json
{
    description: '',
    id: 1,
    title: '',
}
```

{% endtab %}
{% endtabs %}

## Delete a todo item

<mark style="color:red;">`DELETE`</mark> `http://localhost:3000/todos/:todoID`

{% tabs %}
{% tab title="200: OK " %}

{% endtab %}
{% endtabs %}

We can first create a scenario:

```bash
stoobly-agent scenario create create-todo-v1
```

And then record requests into it:

```sh
stoobly-agent record \
    -X POST \
    -d "description=demo&title=test" \
    --scenario-key "<SCENARIO-KEY>" \
    http://localhost:3000/todos

stoobly-agent record \
    --scenario-key "<SCENARIO-KEY>" \
    http://localhost:3000/todos/<TODO-ID>
```

Once we have recorded requests into a scenario, we can replay with:

```sh
stoobly-agent scenario replay "<SCENARIO-KEY>"
```

## Reduce Environment Instability

Depending on a live API service maintained by another can lead to bugs, intermittent failures or latency spikes outside of your control. For example, let's say we want to create a UI form that uses the above API's to create, view, and delete a todo item. Because these features depend on the API, if the service goes down, the UI is unable to progress with work. To reduce downtime, we can use Stoobly to:

1. Record requests to a scenario
2. Toggle Stoobly to mock requests using the recorded scenario
3. Incoming requests that were previously recorded will now return mocked responses

In addition to reducing downtime, using a mock service instead of a shared service for development also imparts folowing benefits:

1. Decreased request latency
2. Consistent responses

A shared API service means other clients are modifying the application's state. The more requests sent to the service, the higher the latency. Furthermore, frequently changing application state can lead to inconsistent responses.


# Scale API Testing

{% hint style="warning" %}
The following requires [experimental features](/experimental/experimental-features)
{% endhint %}

In order to scale API testing, we want to ensure that:

* Tests can be developed quickly
* Minimize maintenance headaches
* Integrate seamlessly into CI & CD pipelines

## Scale Test Development

When testing for functionality, we want to address the following concerns:

* When sending a single request, do we obtain an expected response?
* When sending requests in sequence, do we still obtain expected responses?
* Does our API enforce an accepted list of parameters?

As we write tests to satisfy the above goals, they generally follow the below pattern:

* Send a request with specific parameters
* Validate response
* For each property in the response, check each is expected

The following example illustrates the above pattern.

Given the following endpoint schema:

## Creates a user

<mark style="color:green;">`POST`</mark> `/users`

#### Request Body

| Name        | Type   | Description |
| ----------- | ------ | ----------- |
| first\_name | String |             |
| last\_name  | String |             |
| age         | Number |             |
| country     | String |             |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  first_name: String,
  last_name: String,
  age: Number,
  country: String,
}
```

{% endtab %}
{% endtabs %}

A simple test could be as follows:

```ruby
require 'rails_helper'

RSpec.describe "Users", type: :request do
  describe "POST /users" do
    it "creates successfully" do
      # Send a request with specific parameters
      post "/users", {
        first_name: 'John',
        last_name: 'Smith',
        age: 25,
        country: 'UK',
      }
      
      expect(response.status).to eq(200)
      
      user = JSON.parse(response.body)
      
      # For each property in the response, check that it is expected
      expect(user['first_name']).to eq('John')
      expect(user['last_name']).to eq('Smith')
      expect(user['age']).to eq(25)
      expect(user['country']).to eq('UK')
    end
  end
end
```

Given specific request parameters, we expect a specific response. Seems pretty minimal right? However, there are some critiques:

* The inputs are tightly coupled to the expectations in the form of a contract, i.e. changing an will cause the corresponding expectation to fail
* Each property in the response becomes an expectation
* Imagine having to integrate this request with a GET request for the resource details
* When we think about creating test variations (different charsets, missing fields, empty fields, etc...) we can see how out-of-control this quickly becomes

> What if instead of hard-coding inputs and expected outputs, we record them instead?

Given a driver, e.g. an user interface, Stoobly intercepts and records incoming requests. The received request response becomes the expected test results. A key difference here is that instead of manually specifying all the properties that should match, we use the entire response as the expectation. Now this leads to two potentially problematic scenarios:

1. When a property within the response depends on the value of a previous request
2. When a property within a response is not deterministic (e.g. timestamps)

### Alias Tagging

To address the first problem listed above, we asked ourselves whether we can somehow save the values of a previous request to some variable. The alias feature coming soon captures this very idea. Stoobly provides support for tagging parts of a request such that tagged properties with the same alias name in a successive request will be replaced with values from a previous request. To provide finer grain control on how values are replaced, we also provide various alias resolve strategies.

### Schema Definitions

To address the second problem listed above, we provide dynamically generated endpoint schemas. When an endpoint is created for a request, Stoobly builds a schema definition based on the request parameters and response properties. A request belongs to an endpoint, any schema rules applied to the endpoint gets applied to a request during testing. When a property within a request is marked as not deterministic, it gets skipped.

## Scale Test Maintenance

The following trigger a need for tests to be updated:

* Request parameter changes mean test inputs have to be updated
* Response schema changes mean test expectations have to be updated

For example, below is an updated endpoint schema where we change the casing **first\_name** and **last\_name** to **firstName** and **lastName** respectively:

## Creates a user

<mark style="color:green;">`POST`</mark> `/users`

#### Request Body

| Name                                        | Type   | Description |
| ------------------------------------------- | ------ | ----------- |
| firstName<mark style="color:red;">\*</mark> | String |             |
| lastName<mark style="color:red;">\*</mark>  | String |             |
| age<mark style="color:red;">\*</mark>       | Number |             |
| country<mark style="color:red;">\*</mark>   | String |             |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  firstName: String,
  lastName: String,
  age: Number,
  country: String,
}
```

{% endtab %}
{% endtabs %}

This would then mean that every test where this endpoint is used, needs to be updated. That is, the cost of maintaining tests scales linearly with the number of tests written. The following challenges arise with modifying an endpoint schema:

* Determining which tests need updating
* Updating the test request parameters and expectations

> What if we could use the updated endpoint schema to help pinpoint and update tests that have no longer fulfill the new contract? One significant advantage of typing is so that IDE's can provide static analysis; let Stoobly provide something similar for testing.

To address the challenges with modifying an endpoint schema, Stoobly provides:

* Contract testing to pinpoint which requests no longer adhere to the endpoint schema
* Replay and recording requests with an up-to-date response expectation

## Integrating Tests

To ensure a seamless integration into CI/CD pipelines Stoobly will soon provide the following features:

* Bash CLI to run tests with an exit code of 1 to denote failure
* Configurable JSON output format
* A test result report accessible in the web browser for each run

For power users, we also support lifecycle hooks for fine-grained control on how tests are run. For more information on lifecycle hooks, learn more here:

{% content-ref url="/pages/FShAd4GfCfRCi46Ym2QE" %}
[Lifecycle Hooks](/experimental/experimental-features/api-testing/configuration/lifecycle-hooks)
{% endcontent-ref %}


# Enable E2E Testing

## Current State of E2E Testing

The following table breaks down the testing pyramid. It also provides a summary of the relative proportion of the total test effort each form of testing takes.

<table><thead><tr><th width="137">Test</th><th width="477">Summary</th><th>Percentage</th></tr></thead><tbody><tr><td>Unit</td><td>Test individual components in isolation</td><td>70</td></tr><tr><td>Integration</td><td>Test interactions between multiple components</td><td>20</td></tr><tr><td>E2E</td><td>Test the application from the user's perspective</td><td>10</td></tr></tbody></table>

For applications with little dependence on external API's (third-party services or libraries), most of the expected behavior is defined within the application itself. That is, component input and return value types are owned by the application. In order to validate expected behavior correctness, we need a high degree of test variance to sufficiently cover input to return value mappings.

> **Applications with little dependence on external API's tend to lean more heavily into unit tests.**

Applications with high dependence on external API's, define relatively less new expected behavior and focus instead on integration. For example, a user facing applications may call several external API's and use an externally maintained development framework. There is far less of a concern regarding validating individual component. Instead, the primary concern for the new expected behavior is whether the integration of components meet user needs.

> **Applications with high dependence on external API's should lean more heavily into E2E tests.**

The following table offers a revised relative proportion of the total test effort breakdown for applications with a high dependence on external API's.

<table><thead><tr><th width="137">Test</th><th width="477">Summary</th><th>Percentage</th></tr></thead><tbody><tr><td>Unit</td><td>Test individual components in isolation</td><td>10</td></tr><tr><td>Integration</td><td>Test interactions between multiple components</td><td>20</td></tr><tr><td>E2E</td><td>Test the application from the user's perspective</td><td>70</td></tr></tbody></table>

The above breakdown is an idealized goal of how testing should look like for these types of applications. In reality, there are several barriers to entry that make this breakdown costly to achieve. When E2E testing, we want to address the following barriers to entry:

* How do we ensure tests complete within a reasonable amount time?
* How do we minimize flaky tests?
* How do we minimize CI setup time?

## How Stoobly Helps

### Minimize Run Time

Latency is affected by the following factors:

<table><thead><tr><th width="299">Problem</th><th>Description</th></tr></thead><tbody><tr><td>Distance between client and server</td><td>The further the physical distance, the longer it takes for data to be transferred</td></tr><tr><td>Network congestion</td><td>Increased traffic negatively impacts queing times</td></tr><tr><td>Number of concurrent clients</td><td>Resource bottlenecked APIs may have to service other requests</td></tr><tr><td>Server processing time</td><td>The requested action may have to perform slow actions e.g. reaching out to external APIs</td></tr></tbody></table>

By replacing the live service with a mock service running locally, we can minimize the impact of all the above factors.

<details>

<summary>Distance between client and server</summary>

When mocking, the distance traveled for a request is from the client to agent. By default, the agent is run as a local service.

</details>

<details>

<summary>Network congestion</summary>

Because the agent is run locally, network bandwidth usage should only be affected by other local processes.

</details>

<details>

<summary>Number of concurrent clients</summary>

Because the agent is run locally, the number of concurrent clients talking to the server (the agent in this case) is limited to just you. It no longer scales with the number of team members you have.

</details>

<details>

<summary>Server processing time</summary>

The work done to compute the mock for a request scales logarithmically with the total number of recorded requests. In comparison, the work done by a live service generally scales with a far greater number of factors. These factors include and are not limited to the responsiveness of upstream service dependencies and data source sizes. The larger the number of data sources and the more data each source has, the longer it takes for a service to compute a response.

</details>

### Minimize Flakiness

To minimize flaky tests, we should use mocks in place of calling live services. Examples of live services include authentication, internal API's, and external APIs such as Stripe for payments or Twilio for SMS messages. While depending on live services has the following advantages:

* Maintenance and updates by a dedicated team
* Data created by maintainers

It also incurs the following disadvantages:

* Being down unexpectedly
* Inconsistent responses due to updates to a shared service
* Having long response latencies

These disadvantages are what make E2E tests flaky. To help address the flakiness, we can record requests to create mock APIs. The following provides an overview of how Stoobly can help:

1. Run the E2E test to trigger sending requests
2. Stoobly will intercept the request and record it
3. Configure Stoobly to mock instead of record requests
4. Run E2E tests, API tests, or UI tests

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-f22ff5b70c420894de7231ec06e5313a44136e24%2Fasync-e2e-testing.png?alt=media" alt=""><figcaption></figcaption></figure>

But using in mocks in place of live services may sound counter-intuitive when it comes to E2E testing. After all, isn't the point of E2E testing to validate real user flows? This is true in the case where mocks are consumer generated. Consumer generated mocks have a tendency to not represent real data. That is, consumers likely do not have the same understanding of API responses as the maintainers of the system that produces it. Furthermore, mocks may become out of date as request contracts change.

> **With Stoobly, recorded mocks can be asynchrously validated with API testing.**

### Minimize CI Setup Time

With E2E testing, a common challenge is figuring out how to integrate your tests, your API mocks, and test related infrastructure into a continuous integration (CI) environment. These test environments require the following:

* Dependent services should be running
  * API mocks that represent them must be accessible
* A test runner or pipeline to initiate tests
  * e.g. Cypress, Selenium, Playwright
* Tooling to manage environment configurations

The time required to integrate these parts scale both the number of dependent services as well as with the following challenges:

<table><thead><tr><th width="231">Challenge</th><th>Description</th></tr></thead><tbody><tr><td>Debugability</td><td>When a test fails, easily determine the cause of the failure</td></tr><tr><td>Maintainability</td><td>How quickly can tests or dependent services be modified</td></tr><tr><td>Configuration</td><td>How to separate configuration for different workflows e.g. development and CI</td></tr></tbody></table>

Given the above challenges, developing a robust CI setup for E2E testing can take a few weeks to several months. This depends on the complexity of the application and the number of engineers dedicated to its development.

> **Stoobly helps reduce CI setup time from 2 weeks to 1 day.**

Stoobly simplies the CI setup process to defining service and workflow configurations. With these configurations, Stoobly will generate maintained CI-ready tooling.

## Getting Started

{% content-ref url="/pages/tP6ceRL955iEhJFFSO2W" %}
[How to Scaffold an App](/guides/how-to-integrate-e2e-testing/how-to-scaffold-an-app)
{% endcontent-ref %}


# FAQ

## How do I report an issue?

We track issues in Github at <https://github.com/Stoobly/stoobly-agent/issues>. Please provide as much information as possible and we will take a look :smile:

## Where do I find the latest releases?

pip releases can be found [on PyPI](https://pypi.org/project/stoobly-agent/).

Docker image releases can be found [on Docker Hub](https://hub.docker.com/r/stoobly/agent).

To currently see the agent code changes, see the [Github Releases](https://github.com/Stoobly/stoobly-agent/releases) and their changelogs.

To learn how the contributors publish releases, see our [Developer Guide on Releases](/developer-guide/releases).

## Is this a test framework?

While Stoobly provides similar functionality for running tests and providing test output, our primary goal is to **provide data storage for HTTP(s) requests** from which you can:

* Search requests
* Build requests into scenarios
* Generate endpoint contracts
* Mock requests
* Test request and scenarios

**At its core, Stoobly is an index** where the keys are the request components such as:

* URL, port number, path, headers, query parameters, body

And the returned value is the recorded request's response components:

* headers, body, status code

In regards to mocking and testing, we provide the ability to **dramatically reduce the need to write and maintain request and response components in test code**. Here is how we tackle the core challenges with testing:

1. Generation:
   * Record [requests](/core-concepts/mock-api/requests) and [scenarios](/core-concepts/mock-api/scenarios)
2. Correctness:
   * Replay recorded requests and compare response against recorded response
3. Maintenance:
   * Replay requests to update responses
   * Contract testing to ensure validity of requests and responses

## Where do my requests get stored?

The Stoobly agent records and stores requests to your local machine. We use an underlying SQLite database file to store data. By default it is located at `~/.stoobly/db/stoobly_agent.sqlite3` for Unix systems.

## How much of a request is stored?

We store a HTTP request's - URL, port number, path, headers, query parameters, and body

And the HTTP response's - headers, body, and status code

Certain parts of the request may contain sensitive information. For example an [access token](https://en.wikipedia.org/wiki/Access_token) [passed in with a HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization) might be used for authorization. Another example could be username and password properties being passed in as part of the request body or as form data.

To address this concern, **we provide rewrite and filter rules for each part of the request**. See the following documentation:

## What are common terminologies?

<details>

<summary>Agent</summary>

This refers to the command-line utility `stoobly-agent`. See our [Core Concept Agent documentation](/core-concepts/agent) for more information

</details>

<details>

<summary>CLI</summary>

This is the [command-line interface](https://en.wikipedia.org/wiki/Command-line_interface) that comes with `stoobly-agent` for interacting with Stoobly resources from a terminal or shell.

</details>

<details>

<summary>Proxy</summary>

This refers to the proxy server inside `stoobly-agent` responsible for intercepting, recording, replaying requests, etc.

</details>

<details>

<summary>Request</summary>

Unless specified, a request refers to a [Stoobly Request](/core-concepts/mock-api/requests). Where applicable, the term "HTTP request" represents a request sent via the [HTTP Protocol](https://en.wikipedia.org/wiki/HTTP) to and from various sources and destinations.

</details>

<details>

<summary>Response</summary>

Unless specified, a response refers to a [Stoobly Response](/core-concepts/mock-api/requests/response).

</details>

<details>

<summary>Scenario</summary>

This refers to a collection of requests. See [Scenarios](/core-concepts/mock-api/scenarios) for more details.

</details>

<details>

<summary>UI or Dashboard</summary>

This refers to the `stoobly-agent`'s frontend component built with HTML, CSS and JavaScript.

</details>

<details>

<summary>499 HTTP Status Code</summary>

499 is a custom Stoobly client error response status code. It means that requests are successfully being sent through the `stoobly-agent`proxy. However, the request does not match any previously recorded requests by Stoobly.

This means that Stoobly is installed and working as expected, but there are issues with not found requests.

This occurs when the Mock Policy configuration is set to `all` . This will cause requests that have not been recorded yet to not be found resulting in the 499. If the setting is `found`, then any not found request will go to the remote destination automatically. See the Mock Policy section of [Data Rules](/core-concepts/agent/proxy-settings/data-rules)

To fix this, it is recommended to record the missing requests you're trying to mock.

</details>


# API Testing

## Stoobly API Testing CLI - Questions & Answers

The API testing CLI enables you to validate individual requests and entire scenarios by replaying them and comparing responses against expected outcomes. These testing strategies help ensure API reliability and catch regressions.

***

### Testing Requests

#### Q: How do I test a request to validate its response?

**A:** Use `request test` with the request key to replay and validate the response.

**Example:**

```bash
stoobly-agent request test "<REQUEST-KEY>"
```

#### Q: What test strategies are available?

**A:** Four strategies: `diff` (exact match), `contract` (schema validation), `fuzzy` (flexible match), and `custom` (custom logic).

**Example:**

```bash
# Diff testing (exact comparison, default)
stoobly-agent request test "<REQUEST-KEY>" --strategy diff

# Contract testing (schema validation)
stoobly-agent request test "<REQUEST-KEY>" --strategy contract

# Fuzzy testing (allows minor variations)
stoobly-agent request test "<REQUEST-KEY>" --strategy fuzzy

# Custom testing (use lifecycle hooks)
stoobly-agent request test "<REQUEST-KEY>" --strategy custom --lifecycle-hooks-path ./test-hooks.py
```

#### Q: How do I continue testing even if a test fails?

**A:** Use the `--aggregate-failures` flag to continue execution on failure.

**Example:**

```bash
stoobly-agent request test "<REQUEST-KEY>" --aggregate-failures
```

#### Q: How do I control which test results are displayed?

**A:** Use the `--output-level` option to filter results.

**Example:**

```bash
# Show all tests (passed, failed, skipped)
stoobly-agent request test "<REQUEST-KEY>" --output-level passed

# Show only failed tests
stoobly-agent request test "<REQUEST-KEY>" --output-level failed

# Show only skipped tests
stoobly-agent request test "<REQUEST-KEY>" --output-level skipped
```

#### Q: How do I filter which properties are tested?

**A:** Use the `--filter` option to selectively test properties.

**Example:**

```bash
# Test all properties (default)
stoobly-agent request test "<REQUEST-KEY>" --filter all

# Test only alias properties
stoobly-agent request test "<REQUEST-KEY>" --filter alias

# Test only link properties
stoobly-agent request test "<REQUEST-KEY>" --filter link
```

#### Q: How do I test a request with mock dependencies?

**A:** Use `--response-fixtures-path` or `--public-dir-path` to provide mock responses for dependencies.

**Example:**

```bash
# Use response fixtures
stoobly-agent request test "<REQUEST-KEY>" --response-fixtures-path ./fixtures/responses.yml

# Use public directory for static files
stoobly-agent request test "<REQUEST-KEY>" --public-dir-path ./public

# Use both
stoobly-agent request test "<REQUEST-KEY>" \
  --response-fixtures-path ./fixtures/responses.yml \
  --public-dir-path ./public
```

#### Q: How do I test a request and save the results?

**A:** Use the `--save` flag to persist test results (remote features).

**Example:**

```bash
stoobly-agent request test "<REQUEST-KEY>" --save
```

#### Q: How do I save test results to a specific report?

**A:** Use the `--report-key` option to add results to a report (remote features).

**Example:**

```bash
stoobly-agent request test "<REQUEST-KEY>" --report-key "<REPORT-KEY>"
```

#### Q: How do I test with assigned and validated aliases?

**A:** Combine `--assign` and `--validate` options for comprehensive testing.

**Example:**

```bash
stoobly-agent request test "<REQUEST-KEY>" \
  --assign userId=12345 \
  --assign token=abcde12345 \
  --validate "userId=?int" \
  --validate "token=?string"
```

#### Q: How do I batch test multiple requests?

**A:** Use a script to test multiple requests and collect results.

**Example:**

```bash
#!/bin/bash
# Test all requests in a scenario

scenario_key="<SCENARIO-KEY>"
failed=0

for key in $(stoobly-agent request list --scenario-key $scenario_key --format json | jq -r '.[].id'); do
  echo "Testing request: $key"
  if ! stoobly-agent request test $key --strategy diff; then
    ((failed++))
  fi
done

echo "Tests completed. Failed: $failed"
exit $failed
```

#### Q: How do I use request commands in a CI/CD pipeline?

**A:** Test recorded requests as part of your automated test suite.

**Example:**

```bash
#!/bin/bash
# CI/CD test script

# List all test requests
request_keys=$(stoobly-agent request list --scenario-key "<SCENARIO-KEY>" --format json | jq -r '.[].id')

# Test each request
failed=0
for key in $request_keys; do
  if ! stoobly-agent request test $key --strategy diff --output-level failed; then
    ((failed++))
  fi
done

if [ $failed -gt 0 ]; then
  echo "Failed $failed tests"
  exit 1
fi

echo "All tests passed"
```

#### Q: How do I integrate request testing with monitoring?

**A:** Periodically replay and test requests to monitor API health.

**Example:**

```bash
#!/bin/bash
# Monitoring script

# Replay critical requests
for key in user-login api-health payment-flow; do
  if ! stoobly-agent request test $key --strategy fuzzy --log-level error; then
    # Alert team
    echo "ALERT: Request $key failed"
    # Send notification (email, Slack, PagerDuty, etc.)
  fi
done
```

***

### Testing Scenarios

#### Q: How do I test a scenario to validate responses?

**A:** Use `scenario test` with the scenario key to replay and validate all requests.

**Example:**

```bash
stoobly-agent scenario test "<SCENARIO-KEY>"
```

#### Q: What test strategies are available for scenarios?

**A:** Four strategies: `diff` (exact match), `contract` (schema validation), `fuzzy` (flexible match), and `custom` (custom logic).

**Example:**

```bash
# Diff testing (exact comparison, default)
stoobly-agent scenario test "<SCENARIO-KEY>" --strategy diff

# Contract testing (schema validation)
stoobly-agent scenario test "<SCENARIO-KEY>" --strategy contract

# Fuzzy testing (allows minor variations)
stoobly-agent scenario test "<SCENARIO-KEY>" --strategy fuzzy

# Custom testing (use lifecycle hooks)
stoobly-agent scenario test "<SCENARIO-KEY>" --strategy custom --lifecycle-hooks-path ./test-hooks.py
```

#### Q: How do I continue testing even if a request fails?

**A:** Use the `--aggregate-failures` flag to continue execution on failure.

**Example:**

```bash
stoobly-agent scenario test "<SCENARIO-KEY>" --aggregate-failures
```

#### Q: How do I control which test results are displayed?

**A:** Use the `--output-level` option to filter results.

**Example:**

```bash
# Show all tests (passed, failed, skipped, default)
stoobly-agent scenario test "<SCENARIO-KEY>" --output-level passed

# Show only failed tests
stoobly-agent scenario test "<SCENARIO-KEY>" --output-level failed

# Show only skipped tests
stoobly-agent scenario test "<SCENARIO-KEY>" --output-level skipped
```

#### Q: How do I filter which properties are tested?

**A:** Use the `--filter` option to selectively test properties.

**Example:**

```bash
# Test all properties (default)
stoobly-agent scenario test "<SCENARIO-KEY>" --filter all

# Test only alias properties
stoobly-agent scenario test "<SCENARIO-KEY>" --filter alias

# Test only link properties
stoobly-agent scenario test "<SCENARIO-KEY>" --filter link
```

#### Q: How do I test a scenario with mock dependencies?

**A:** Use `--response-fixtures-path` or `--public-dir-path` to provide mock responses.

**Example:**

```bash
# Use response fixtures
stoobly-agent scenario test "<SCENARIO-KEY>" --response-fixtures-path ./fixtures/responses.yml

# Use public directory for static files
stoobly-agent scenario test "<SCENARIO-KEY>" --public-dir-path ./public

# Use both
stoobly-agent scenario test "<SCENARIO-KEY>" \
  --response-fixtures-path ./fixtures/responses.yml \
  --public-dir-path ./public
```

#### Q: How do I save test results to a report?

**A:** Use the `--report-key` option to add results to a report (remote features).

**Example:**

```bash
stoobly-agent scenario test "<SCENARIO-KEY>" --report-key "<REPORT-KEY>"
```

#### Q: How do I save test results?

**A:** Use the `--save` flag to persist test results (remote features).

**Example:**

```bash
stoobly-agent scenario test "<SCENARIO-KEY>" --save
```

***

### Environment-Specific Testing

#### Q: How do I run the same scenario test against different environments?

**A:** Use the `--host` option to target different environments.

**Example:**

```bash
# Test against local
stoobly-agent scenario test "<SCENARIO-KEY>" --host localhost:8080

# Test against staging
stoobly-agent scenario test "<SCENARIO-KEY>" --host staging.example.com

# Test against production
stoobly-agent scenario test "<SCENARIO-KEY>" --host api.example.com
```

#### Q: How do I create environment-specific test scenarios?

**A:** Create separate scenarios for each environment or use the same scenario with different hosts.

**Example:**

```bash
# Option 1: Separate scenarios
stoobly-agent scenario create "Login Flow - Local"
stoobly-agent scenario create "Login Flow - Staging"
stoobly-agent scenario create "Login Flow - Production"

# Option 2: One scenario, different hosts
stoobly-agent scenario create "Login Flow"
# Use with different hosts:
stoobly-agent scenario test login-flow --host localhost:8080
stoobly-agent scenario test login-flow --host staging.example.com
```

***

### CI/CD Integration

#### Q: How do I use scenario tests in CI/CD pipelines?

**A:** Test scenarios as part of your automated test suite.

**Example:**

```bash
#!/bin/bash
# CI/CD test script

# Test critical scenarios
scenarios=(
  "user-registration"
  "user-login"
  "checkout-flow"
  "admin-operations"
)

failed=0
for scenario in "${scenarios[@]}"; do
  echo "Testing: $scenario"
  if ! stoobly-agent scenario test $scenario --strategy diff --output-level failed; then
    ((failed++))
    echo "❌ Failed: $scenario"
  else
    echo "✅ Passed: $scenario"
  fi
done

if [ $failed -gt 0 ]; then
  echo "Failed $failed scenario(s)"
  exit 1
fi

echo "All scenarios passed!"
```

#### Q: How do I generate test reports from scenario tests?

**A:** Use JSON format and process the output.

**Example:**

```bash
#!/bin/bash
# Generate test report

timestamp=$(date +%Y%m%d_%H%M%S)
report_file="test-report-${timestamp}.json"

# Run tests and capture output
stoobly-agent scenario test "<SCENARIO-KEY>" --format json > "$report_file"

# Process results
passed=$(jq '[.results[] | select(.status=="passed")] | length' "$report_file")
failed=$(jq '[.results[] | select(.status=="failed")] | length' "$report_file")

echo "Test Report: $passed passed, $failed failed"
echo "Full report: $report_file"
```

***

### Advanced Testing Operations

#### Q: How do I chain multiple test scenarios?

**A:** Use a script to execute scenarios in sequence with dependency handling.

**Example:**

```bash
#!/bin/bash
# Chain scenarios with dependencies

# Setup scenario
stoobly-agent scenario replay setup-data --save
if [ $? -ne 0 ]; then
  echo "Setup failed"
  exit 1
fi

# Main test scenario
stoobly-agent scenario test main-flow --strategy diff
if [ $? -ne 0 ]; then
  echo "Main flow failed"
  exit 1
fi

# Cleanup scenario
stoobly-agent scenario replay cleanup --save

echo "All scenarios completed"
```

#### Q: How do I conditionally execute test scenarios?

**A:** Use scripts with conditional logic based on scenario results.

**Example:**

```bash
#!/bin/bash
# Conditional scenario execution

# Run smoke tests first
if stoobly-agent scenario test smoke-tests --output-level failed; then
  echo "Smoke tests passed, running full suite"
  stoobly-agent scenario test full-test-suite
else
  echo "Smoke tests failed, skipping full suite"
  exit 1
fi
```

***

### Monitoring and Debugging

#### Q: How do I debug a failing scenario test?

**A:** Increase log level and use verbose output.

**Example:**

```bash
# Debug with verbose logging
stoobly-agent scenario test "<SCENARIO-KEY>" --log-level debug --output-level failed

# Replay with logging to see each request
stoobly-agent scenario replay "<SCENARIO-KEY>" --log-level info
```

#### Q: How do I identify which request in a scenario test is failing?

**A:** Use detailed output and logging to track request execution.

**Example:**

```bash
# Test with all output levels
stoobly-agent scenario test "<SCENARIO-KEY>" --output-level passed --log-level info

# This shows each request as it executes and its result
```

#### Q: How do I monitor scenario test health over time?

**A:** Set up periodic scenario testing with result tracking.

**Example:**

```bash
#!/bin/bash
# Monitoring script

while true; do
  timestamp=$(date +%Y-%m-%d_%H:%M:%S)
  
  if stoobly-agent scenario test health-check --strategy fuzzy; then
    echo "$timestamp - HEALTHY"
  else
    echo "$timestamp - UNHEALTHY - ALERT SENT"
    # Send alert (email, Slack, PagerDuty, etc.)
  fi
  
  sleep 300  # Check every 5 minutes
done
```

***


# CA Cert

## Stoobly CA Certificate CLI - Questions & Answers

The CA certificate CLI manages SSL/TLS certificate authority operations for intercepting HTTPS traffic. Installing the CA certificate allows Stoobly to decrypt and inspect HTTPS requests for recording, mocking, and testing.

***

### Understanding CA Certificates

#### Q: What is a CA certificate?

**A:** A CA (Certificate Authority) certificate is a root certificate that allows Stoobly to create valid SSL certificates for intercepting HTTPS traffic. It enables the proxy to decrypt, inspect, and re-encrypt HTTPS requests.

**Example:**

```bash
# Install CA certificate to enable HTTPS interception
stoobly-agent ca-cert install
```

#### Q: Why do I need to install a CA certificate?

**A:** Installing the CA certificate allows Stoobly to intercept HTTPS traffic. Without it, you can only record and mock HTTP (non-encrypted) requests.

**Example:**

```bash
# Without CA cert: Only HTTP works
stoobly-agent record http://api.example.com/users

# With CA cert: Both HTTP and HTTPS work
stoobly-agent ca-cert install
stoobly-agent record https://api.example.com/users  # Now works!
```

#### Q: Is it safe to install the CA certificate?

**A:** Yes, the CA certificate is only installed on your local machine and is only trusted by your system. It's used solely for local development and testing. Remove it when done with `ca-cert uninstall`.

**Example:**

```bash
# Install for testing
stoobly-agent ca-cert install

# When done, uninstall
stoobly-agent ca-cert uninstall
```

***

### Installing CA Certificate

#### Q: How do I install the CA certificate?

**A:** Use `ca-cert install` to install the certificate authority certificate on your system.

**Example:**

```bash
stoobly-agent ca-cert install
```

#### Q: Where does the CA certificate get installed?

**A:** The CA certificate is installed in your system's trusted certificate store. The location varies by operating system:

* **macOS**: Keychain Access
* **Linux**: `/usr/local/share/ca-certificates/` or system store
* **Windows**: Certificate Manager

**Example:**

```bash
# Install CA cert
stoobly-agent ca-cert install

# On macOS, verify in Keychain Access
open -a "Keychain Access"
# Search for "stoobly" or "mitmproxy"

# On Linux, check system certificates
ls /usr/local/share/ca-certificates/
```

#### Q: Do I need sudo/admin privileges to install the CA certificate?

**A:** Yes, installing system certificates typically requires administrative privileges.

**Example:**

```bash
# May prompt for password
stoobly-agent ca-cert install

# On Linux, might need sudo
sudo stoobly-agent ca-cert install
```

#### Q: How do I install the CA certificate to a custom directory?

**A:** Use the `--ca-certs-dir-path` option to specify where the CA certificate files are stored.

**Example:**

```bash
# Install from custom directory
stoobly-agent ca-cert install --ca-certs-dir-path /path/to/custom/ca-certs
```

#### Q: What happens during CA certificate installation?

**A:** The installation process creates the CA certificate (if not exists), adds it to your system's trust store, and configures it to be trusted for SSL/TLS connections.

**Example:**

```bash
stoobly-agent ca-cert install
# Output:
# Generating CA certificate...
# Installing CA certificate to system trust store...
# CA certificate installed successfully!
```

***

### Viewing Certificate Path

#### Q: How do I find the path to the CA certificate file?

**A:** Use `ca-cert show` with the `--format` option to output the path to the certificate file in the specified format.

**Example:**

```bash
# Show path to PEM format certificate
stoobly-agent ca-cert show --format pem
# Output: /home/user/.stoobly/ca_certs/mitmproxy-ca-cert.pem

# Show path to CER format certificate
stoobly-agent ca-cert show --format cer
# Output: /home/user/.stoobly/ca_certs/mitmproxy-ca-cert.cer

# Show path to P12 format certificate
stoobly-agent ca-cert show --format p12
# Output: /home/user/.stoobly/ca_certs/mitmproxy-ca-cert.p12
```

#### Q: What certificate formats are available?

**A:** The `show` command supports three formats: `cer`, `p12`, and `pem`. Each format has different use cases.

**Example:**

```bash
# PEM format (most common, used by many tools)
stoobly-agent ca-cert show --format pem

# CER format (common on Windows/macOS)
stoobly-agent ca-cert show --format cer

# P12 format (PKCS#12, contains private key)
stoobly-agent ca-cert show --format p12
```

#### Q: How do I use the certificate path in scripts?

**A:** The `show` command outputs only the path to stdout, making it ideal for scripting and command substitution.

**Example:**

```bash
# Use in a script to copy certificate
CERT_PATH=$(stoobly-agent ca-cert show --format pem)
cp "$CERT_PATH" /path/to/destination/

# Use with command substitution in Linux installation
sudo cp $(stoobly-agent ca-cert show --format pem) /usr/local/share/ca-certificates/mitmproxy-ca-cert.crt
sudo update-ca-certificates

# Use in environment variable
export CA_CERT_PATH=$(stoobly-agent ca-cert show --format pem)
echo "Certificate at: $CA_CERT_PATH"
```

#### Q: What happens if the certificate doesn't exist?

**A:** The `show` command will output an error message and exit with a non-zero status if the certificate file is not found.

**Example:**

```bash
stoobly-agent ca-cert show --format pem
# Output (if not found):
# Certificate file not found: /path/to/cert.pem
# Run 'stoobly-agent ca-cert install' to generate certificates.

# Check exit status
echo $?
# Output: 1 (error)
```

#### Q: How do I specify a custom CA certs directory?

**A:** Use the `--ca-certs-dir-path` option to search for certificates in a custom directory.

**Example:**

```bash
# Show certificate from custom directory
stoobly-agent ca-cert show --format pem --ca-certs-dir-path /path/to/custom/ca-certs

# Use in script with custom path
CERT_PATH=$(stoobly-agent ca-cert show --format pem --ca-certs-dir-path ~/.custom-stoobly/ca_certs)
```

#### Q: When should I use the show command?

**A:** Use `ca-cert show` when you need the certificate path for manual import (e.g., Firefox), scripting, or when referencing the certificate in other tools.

**Example:**

```bash
# For Firefox manual import
FIREFOX_CERT=$(stoobly-agent ca-cert show --format pem)
# Then import $FIREFOX_CERT in Firefox settings

# For automated deployment scripts
CERT_PATH=$(stoobly-agent ca-cert show --format pem)
scp "$CERT_PATH" server:/tmp/stoobly-ca.pem

# For verification
if stoobly-agent ca-cert show --format pem > /dev/null 2>&1; then
    echo "Certificate exists"
else
    echo "Certificate not found, installing..."
    stoobly-agent ca-cert install
fi
```

***

### Creating SSL Certificates

#### Q: How do I create an SSL certificate for a hostname?

**A:** Use `ca-cert mkcert` with the hostname to generate a signed certificate.

**Example:**

```bash
# Create certificate for a domain
stoobly-agent ca-cert mkcert api.example.com
```

#### Q: How do I create certificates for multiple hostnames?

**A:** Run mkcert for each hostname you need to intercept.

**Example:**

```bash
# Create certificates for multiple domains
stoobly-agent ca-cert mkcert api.example.com
stoobly-agent ca-cert mkcert frontend.example.com
stoobly-agent ca-cert mkcert admin.example.com
```

#### Q: How do I create a wildcard certificate?

**A:** Use wildcard notation with the asterisk (\*) for the subdomain.

**Example:**

```bash
# Wildcard certificate for all subdomains
stoobly-agent ca-cert mkcert "*.example.com"

# Now works for: api.example.com, app.example.com, etc.
```

#### Q: Where are the generated certificates stored?

**A:** Certificates are stored in the certs directory (default: `~/.stoobly/certs/`).

**Example:**

```bash
# Create certificate (stored in default location)
stoobly-agent ca-cert mkcert api.example.com

# Check generated certificates
ls ~/.stoobly/certs/
# api.example.com.pem
# api.example.com-key.pem
```

#### Q: How do I specify a custom output directory for certificates?

**A:** Use the `--certs-dir-path` option to specify where certificates should be saved.

**Example:**

```bash
stoobly-agent ca-cert mkcert api.example.com --certs-dir-path /path/to/output
```

#### Q: How do I specify a custom CA certs directory?

**A:** Use the `--ca-certs-dir-path` option to use a different CA certificate for signing.

**Example:**

```bash
stoobly-agent ca-cert mkcert api.example.com \
  --ca-certs-dir-path /path/to/ca-certs \
  --certs-dir-path /path/to/output
```

***

### Uninstalling CA Certificate

#### Q: How do I uninstall the CA certificate?

**A:** Use `ca-cert uninstall` to remove the certificate from your system (coming soon).

**Example:**

```bash
# Uninstall CA certificate
stoobly-agent ca-cert uninstall
# Output: Not yet implemented. Stay tuned!
```

#### Q: How do I manually remove the CA certificate?

**A:** Manually remove it from your system's certificate store until uninstall is implemented.

**Example:**

```bash
# macOS: Use Keychain Access
# 1. Open Keychain Access
# 2. Search for "stoobly" or "mitmproxy"
# 3. Delete the certificate

# Linux: Remove from certificate directory
sudo rm /usr/local/share/ca-certificates/stoobly-ca.crt
sudo update-ca-certificates

# Windows: Use Certificate Manager (certmgr.msc)
# 1. Open Certificate Manager
# 2. Navigate to Trusted Root Certification Authorities
# 3. Find and delete the Stoobly/mitmproxy certificate
```

***

### Workflow Integration

#### Q: When should I install the CA certificate?

**A:** Install it before recording or testing HTTPS traffic. It's typically done once per machine during initial setup.

**Example:**

```bash
# Initial setup
stoobly-agent ca-cert install

# Now you can record HTTPS
stoobly-agent run --intercept --intercept-mode record
```

#### Q: How do I use CA certificates with scaffold workflows?

**A:** The scaffold workflow automatically prompts for CA certificate installation when needed.

**Example:**

```bash
# Start scaffold workflow
stoobly-agent scaffold workflow up record --app-dir-path ./my-app
# Prompt: Installing CA certificate is required for recording requests, continue? (y/N)

# Or skip prompt with environment variable
export STOOBLY_CA_CERTS_INSTALL_CONFIRM=y
stoobly-agent scaffold workflow up record --app-dir-path ./my-app

# Or using Makefile
make -f .stoobly/services/.Makefile record
```

#### Q: How do I verify the CA certificate is installed?

**A:** Try recording HTTPS traffic. If it works without certificate errors, the CA cert is properly installed.

**Example:**

```bash
# Test HTTPS recording
stoobly-agent run --intercept --intercept-mode record

# In another terminal, try recording HTTPS
stoobly-agent record https://api.example.com/test

# If successful, CA cert is working
```

***

### Troubleshooting

#### Q: What do I do if HTTPS recording fails?

**A:** Ensure the CA certificate is installed and trusted by your system.

**Example:**

```bash
# Reinstall CA certificate
stoobly-agent ca-cert install

# Check if certificate exists
ls ~/.mitmproxy/
# Should see: mitmproxy-ca.pem, mitmproxy-ca-cert.pem

# Try recording again
stoobly-agent record https://api.example.com/users
```

#### Q: What if I get SSL verification errors?

**A:** The CA certificate may not be properly trusted. Reinstall or manually verify in your system's certificate store.

**Example:**

```bash
# Reinstall
stoobly-agent ca-cert install

# On macOS, verify trust settings in Keychain Access
open -a "Keychain Access"
# Find certificate → Get Info → Trust → "Always Trust"

# On Linux, update certificates
sudo update-ca-certificates
```

#### Q: Why does my Node.js process still get certificate errors after installing the CA certificate?

**A:** `ca-cert install` adds the certificate to your system's trust store, which browsers (Chrome, Edge, Safari) and most OS-level tools read from. Node.js doesn't consult that store — it uses its own bundled CA list — so a Node process making HTTPS requests through the Stoobly proxy (a dev server, a script, a non-browser test runner) will still reject Stoobly's certificate even though the browser trusts it fine. Point Node at the certificate explicitly with `NODE_EXTRA_CA_CERTS`.

**Example:**

```bash
# Get the certificate path
CERT_PATH=$(stoobly-agent ca-cert show --format pem)

# Trust it for this Node process
NODE_EXTRA_CA_CERTS="$CERT_PATH" node server.js
```

As a quicker but less safe alternative, `NODE_TLS_REJECT_UNAUTHORIZED=0` disables certificate verification for the whole process — it accepts any certificate, not just Stoobly's, so only use it in local/throwaway dev or test environments, never for anything that also talks to real external services.

```bash
# Less safe — skips all certificate verification, not just Stoobly's
NODE_TLS_REJECT_UNAUTHORIZED=0 node server.js
```

#### Q: How do I handle multiple CA certificates?

**A:** Use different `--ca-certs-dir-path` for different projects or environments.

**Example:**

```bash
# Project A
stoobly-agent ca-cert install --ca-certs-dir-path ~/project-a/.stoobly/ca_certs

# Project B
stoobly-agent ca-cert install --ca-certs-dir-path ~/project-b/.stoobly/ca_certs

# Use with specific project
stoobly-agent run --ca-certs-dir-path ~/project-a/.stoobly/ca_certs
```

#### Q: What do I do if certificate installation fails?

**A:** Check for permission issues, ensure the directory exists, and verify you have admin privileges.

**Example:**

```bash
# Create directory if missing
mkdir -p ~/.stoobly/ca_certs

# Try with sudo (Linux)
sudo stoobly-agent ca-cert install

# Check for errors
stoobly-agent ca-cert install --ca-certs-dir-path ~/.stoobly/ca_certs
```

***

### Browser Configuration

#### Q: Do I need to configure my browser after installing the CA certificate?

**A:** Most browsers use the system certificate store, but some (like Firefox) use their own. You may need to import the certificate manually.

**Example:**

```bash
# For Firefox:
# 1. Go to Settings → Privacy & Security → Certificates → View Certificates
# 2. Click "Import"
# 3. Select: ~/.mitmproxy/mitmproxy-ca-cert.pem
# 4. Trust for identifying websites
```

#### Q: How do I test if my browser trusts the CA certificate?

**A:** Start Stoobly proxy and visit an HTTPS site through it. If no certificate warning appears, it's working.

**Example:**

```bash
# Start proxy
stoobly-agent run --headless

# Configure browser proxy to localhost:8080
# Visit: https://example.com
# No certificate warning = CA cert is trusted
```

***

### Team Collaboration

#### Q: Do team members need to install the CA certificate?

**A:** Yes, each team member needs to install the CA certificate on their machine to intercept HTTPS traffic.

**Example:**

```bash
# Each team member runs:
stoobly-agent ca-cert install

# Now everyone can record/test HTTPS
```

#### Q: Can I share CA certificate files with my team?

**A:** You can share the CA certificate files, but each team member still needs to install them on their system.

**Example:**

```bash
# Share via git (optional - for custom CA)
git add .stoobly/ca_certs/
git commit -m "Add shared CA certificate"

# Team members install
git pull
stoobly-agent ca-cert install --ca-certs-dir-path ./.stoobly/ca_certs
```

#### Q: Should CA certificates be committed to version control?

**A:** Generally no, as they're generated per machine. However, for team consistency, you can share a common CA certificate by committing it.

**Example:**

```bash
# .gitignore (typical setup)
.stoobly/ca_certs/  # Don't commit

# OR for team sharing:
# Remove .stoobly/ca_certs/ from .gitignore
# Commit shared CA certificate
git add .stoobly/ca_certs/
git commit -m "Add shared CA certificate for team"
```

***

### CI/CD Integration

#### Q: How do I handle CA certificates in CI/CD?

**A:** Install the CA certificate in the CI environment before running tests.

**Example:**

```bash
#!/bin/bash
# CI/CD script

# Install CA certificate
stoobly-agent ca-cert install --ca-certs-dir-path ./ci-ca-certs

# Run tests with HTTPS
stoobly-agent run --intercept --intercept-mode test &
AGENT_PID=$!

# Wait for agent to start
sleep 2

# Run test suite
npm test

# Cleanup
kill $AGENT_PID
```

#### Q: How do I use certificates in Docker containers?

**A:** Mount the CA certificate directory and install it in the container.

**Example:**

```dockerfile
# Dockerfile
FROM python:3.14

# Install stoobly-agent
RUN pip install stoobly-agent

# Copy CA certificate
COPY .stoobly/ca_certs /app/.stoobly/ca_certs

# Install CA certificate
RUN stoobly-agent ca-cert install --ca-certs-dir-path /app/.stoobly/ca_certs

# Run your application
CMD ["your-app"]
```

***

### Security Considerations

#### Q: Is the CA certificate secure?

**A:** The CA certificate is only trusted on your local machine. However, anyone with access to the private key could intercept your HTTPS traffic, so protect the certificate files.

**Example:**

```bash
# Protect CA certificate files
chmod 600 ~/.mitmproxy/mitmproxy-ca.pem
chmod 600 ~/.mitmproxy/mitmproxy-ca-cert.pem

# Don't share private keys publicly
echo ".stoobly/ca_certs/" >> .gitignore
```

#### Q: Should I use the same CA certificate in production?

**A:** No! The CA certificate is for local development and testing only. Never use it in production environments.

**Example:**

```bash
# Development only
stoobly-agent ca-cert install

# Production: Use proper SSL certificates from trusted CAs
# (Let's Encrypt, DigiCert, etc.)
```

#### Q: How do I rotate CA certificates?

**A:** Delete old certificates and generate new ones.

**Example:**

```bash
# Remove old CA certificate
rm -rf ~/.mitmproxy/
rm -rf ~/.stoobly/ca_certs/

# Generate and install new one
stoobly-agent ca-cert install

# Regenerate host certificates
stoobly-agent ca-cert mkcert api.example.com
```

***

### Quick Reference

#### Q: What are the most common ca-cert commands?

**A:** Here's a quick reference of frequently used commands:

**Example:**

```bash
# Install CA certificate (required for HTTPS)
stoobly-agent ca-cert install

# Install to custom directory
stoobly-agent ca-cert install --ca-certs-dir-path /path/to/ca-certs

# Show certificate path
stoobly-agent ca-cert show --format pem
stoobly-agent ca-cert show --format cer
stoobly-agent ca-cert show --format p12

# Create certificate for hostname
stoobly-agent ca-cert mkcert api.example.com

# Create wildcard certificate
stoobly-agent ca-cert mkcert "*.example.com"

# Create certificate with custom paths
stoobly-agent ca-cert mkcert api.example.com \
  --ca-certs-dir-path /path/to/ca-certs \
  --certs-dir-path /path/to/output

# Uninstall CA certificate (coming soon)
stoobly-agent ca-cert uninstall
```

***

### Complete Setup Example

#### Q: What's the complete workflow for setting up CA certificates?

**A:** Install CA cert → Create host certificates → Configure proxy → Test HTTPS.

**Example:**

```bash
# Step 1: Install CA certificate
stoobly-agent ca-cert install

# Step 2: Create certificates for your domains (optional, auto-generated by proxy)
stoobly-agent ca-cert mkcert api.example.com
stoobly-agent ca-cert mkcert "*.myapp.local"

# Step 3: Start Stoobly proxy
stoobly-agent run --intercept --intercept-mode record

# Step 4: Configure your app to use proxy (localhost:8080)
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080

# Step 5: Make HTTPS requests (they get intercepted)
curl https://api.example.com/users

# Step 6: View recorded requests
stoobly-agent request list
```

***

### Platform-Specific Notes

#### Q: Are there any macOS-specific considerations?

**A:** On macOS, you may need to approve the certificate in Keychain Access and restart your browser.

**Example:**

```bash
# Install on macOS
stoobly-agent ca-cert install

# Open Keychain Access to verify
open -a "Keychain Access"

# Find "mitmproxy" certificate
# Double-click → Trust → "Always Trust"
# Close Keychain Access (it saves automatically)

# Restart browsers for changes to take effect
```

#### Q: Are there any Linux-specific considerations?

**A:** On Linux, you may need to update the certificate store after installation.

**Example:**

```bash
# Install on Linux
sudo stoobly-agent ca-cert install

# Update certificate store
sudo update-ca-certificates

# For Firefox, import manually
# Settings → Privacy & Security → Certificates → View Certificates → Import
# Select: ~/.mitmproxy/mitmproxy-ca-cert.pem
```

#### Q: Are there any Windows-specific considerations?

**A:** On Windows, you may need to run the command prompt as Administrator.

**Example:**

```bash
# Run Command Prompt as Administrator
# Right-click → "Run as administrator"

# Install CA certificate
stoobly-agent ca-cert install

# Certificate is added to Windows Certificate Store
# View: certmgr.msc → Trusted Root Certification Authorities
```


# Config

## Stoobly Config CLI - Questions & Answers

The config CLI manages Stoobly configuration including proxy settings, scenarios, rewrite rules, match rules, filter rules, and project settings. It allows runtime configuration of the agent without editing files directly.

***

### Understanding Configuration

#### Q: What is Stoobly configuration?

**A:** Configuration controls how Stoobly intercepts, modifies, and routes HTTP requests. It includes rewrite rules for transforming requests, match rules for identifying requests, and filter rules for filtering traffic.

**Example:**

```bash
# View current configuration
stoobly-agent setting dump

# View configuration directory
stoobly-agent setting dump --dir
```

#### Q: Where is configuration stored?

**A:** Configuration is stored in the `.stoobly` directory, typically in `~/.stoobly/settings.yml` or your project's `.stoobly/settings.yml`.

**Example:**

```bash
# View config directory location
stoobly-agent setting dump --dir
# Output: /home/user/.stoobly

# View full configuration
stoobly-agent setting dump
```

***

### Viewing and Managing Configuration

#### Q: How do I view the current configuration?

**A:** Use `setting dump` to display all configuration settings.

**Example:**

```bash
# Display configuration as JSON
stoobly-agent setting dump
```

#### Q: How do I save configuration to a file?

**A:** Use the `--save-to-file` flag to export configuration.

**Example:**

```bash
# Save to timestamped file
stoobly-agent setting dump --save-to-file
# Output: Config successfully dumped to stoobly_agent_config_dump_1234567890.json

# View the file
cat stoobly_agent_config_dump_*.json
```

#### Q: How do I reset configuration to defaults?

**A:** Use `config reset` to restore default settings.

**Example:**

```bash
stoobly-agent setting reset
# Output: Reset /home/user/.stoobly/settings.yml to defaults.
```

#### Q: How do I validate my configuration?

**A:** Use `config validate` to check for configuration errors.

**Example:**

```bash
stoobly-agent setting validate
```

***

### Managing Active Scenario

#### Q: How do I set the active scenario?

**A:** Use `config scenario set` with the scenario key to make it active for intercept operations.

**Example:**

```bash
stoobly-agent setting scenario set "<SCENARIO-KEY>"
# Output: Scenario updated!
```

#### Q: How do I view the currently active scenario?

**A:** Use `config scenario show` to display active scenario details.

**Example:**

```bash
stoobly-agent setting scenario show
```

#### Q: How do I clear the active scenario?

**A:** Use `config scenario clear` to remove the active scenario setting.

**Example:**

```bash
stoobly-agent setting scenario clear
# Output: Scenario cleared!
```

#### Q: Why would I set an active scenario?

**A:** Setting an active scenario directs all intercepted requests to that scenario automatically, useful for organizing recorded requests during development.

**Example:**

```bash
# Set active scenario
stoobly-agent setting scenario set user-login-flow

# Start intercepting
stoobly-agent run --intercept --intercept-mode record

# All recorded requests go to user-login-flow scenario
```

***

### Rewrite Rules

#### Q: What are rewrite rules?

**A:** Rewrite rules transform HTTP requests in flight, allowing you to modify URLs, headers, query parameters, or body parameters before they're sent or matched.

**Example:**

```bash
# Rewrite host from old to new
stoobly-agent setting rewrite set \
  --pattern "https://old-api.example.com/.*" \
  --method GET \
  --method POST \
  --mode mock \
  --mode record \
  --hostname new-api.example.com
```

#### Q: How do I create a rewrite rule to change the hostname?

**A:** Use `config rewrite set` with `--hostname` option.

**Example:**

```bash
stoobly-agent setting rewrite set \
  --pattern "https://api.example.com/.*" \
  --method GET \
  --method POST \
  --mode mock \
  --hostname api-staging.example.com
```

#### Q: How do I create a rewrite rule to change the URL path?

**A:** Use the `--path` option to specify the new path.

**Example:**

```bash
# Rewrite /v1/users to /v2/users
stoobly-agent setting rewrite set \
  --pattern "https://api.example.com/v1/users" \
  --method GET \
  --mode mock \
  --mode record \
  --path "/v2/users"
```

#### Q: How do I create a rewrite rule to change the scheme?

**A:** Use the `--scheme` option to switch between http and https.

**Example:**

```bash
# Change https to http
stoobly-agent setting rewrite set \
  --pattern "https://api.example.com/.*" \
  --method GET \
  --mode mock \
  --scheme http
```

#### Q: How do I create a rewrite rule to change the port?

**A:** Use the `--port` option to specify a different port.

**Example:**

```bash
# Redirect to different port
stoobly-agent setting rewrite set \
  --pattern "https://api.example.com/.*" \
  --method GET \
  --mode mock \
  --port 8443
```

#### Q: How do I rewrite request headers?

**A:** Use `--type header` with `--name` and `--value` options.

**Example:**

```bash
# Add/modify Authorization header
stoobly-agent setting rewrite set \
  --pattern "https://api.example.com/.*" \
  --method GET \
  --method POST \
  --mode mock \
  --mode record \
  --type header \
  --name "Authorization" \
  --value "Bearer new-token"
```

#### Q: How do I rewrite query parameters?

**A:** Use `--type query_param` with parameter name and value.

**Example:**

```bash
# Rewrite api_key query parameter
stoobly-agent setting rewrite set \
  --pattern "https://api.example.com/.*" \
  --method GET \
  --mode mock \
  --type query_param \
  --name "api_key" \
  --value "test-key-123"
```

#### Q: How do I rewrite body parameters?

**A:** Use `--type body_param` for POST/PUT request body parameters.

**Example:**

```bash
# Rewrite userId in request body
stoobly-agent setting rewrite set \
  --pattern "https://api.example.com/users" \
  --method POST \
  --mode record \
  --type body_param \
  --name "userId" \
  --value "test-user-123"
```

#### Q: How do I rewrite response headers?

**A:** Use `--type response_header` to modify response headers.

**Example:**

```bash
# Add custom response header
stoobly-agent setting rewrite set \
  --pattern "https://api.example.com/.*" \
  --method GET \
  --mode mock \
  --type response_header \
  --name "X-Custom-Header" \
  --value "custom-value"
```

#### Q: How do I rewrite response parameters?

**A:** Use `--type response_param` to modify response body parameters.

**Example:**

```bash
# Rewrite response data
stoobly-agent setting rewrite set \
  --pattern "https://api.example.com/.*" \
  --method GET \
  --mode mock \
  --type response_param \
  --name "status" \
  --value "success"
```

#### Q: How do I apply rewrite rules to specific modes?

**A:** Use multiple `--mode` options to specify which intercept modes the rule applies to.

**Example:**

```bash
# Apply only to mock and test modes
stoobly-agent setting rewrite set \
  --pattern "https://api.example.com/.*" \
  --method GET \
  --mode mock \
  --mode test \
  --hostname localhost:8080
```

#### Q: How do I create rewrite rules for specific HTTP methods?

**A:** Use multiple `--method` options to target specific methods.

**Example:**

```bash
# Apply to GET and POST only
stoobly-agent setting rewrite set \
  --pattern "https://api.example.com/.*" \
  --method GET \
  --method POST \
  --mode mock \
  --hostname api-mock.local
```

***

### Match Rules

#### Q: What are match rules?

**A:** Match rules determine which request components (headers, query params, body params) are used to match requests to recorded responses during mocking or testing.

**Example:**

```bash
# Match by query parameters and headers
stoobly-agent setting match set \
  --pattern "https://api.example.com/users" \
  --method GET \
  --mode mock \
  --component query_param \
  --component header
```

#### Q: How do I create a match rule to ignore certain components?

**A:** Specify only the components you want to match; unspecified components are ignored.

**Example:**

```bash
# Match only by path, ignore query params
stoobly-agent setting match set \
  --pattern "https://api.example.com/search" \
  --method GET \
  --mode mock
  # No --component means match by path/method only
```

#### Q: How do I match by query parameters?

**A:** Use `--component query_param` to include query parameters in matching.

**Example:**

```bash
stoobly-agent setting match set \
  --pattern "https://api.example.com/search" \
  --method GET \
  --mode mock \
  --component query_param
```

#### Q: How do I match by headers?

**A:** Use `--component header` to include headers in matching.

**Example:**

```bash
# Match by Authorization header
stoobly-agent setting match set \
  --pattern "https://api.example.com/.*" \
  --method GET \
  --method POST \
  --mode mock \
  --component header
```

#### Q: How do I match by body parameters?

**A:** Use `--component body_param` for POST/PUT request body matching.

**Example:**

```bash
stoobly-agent setting match set \
  --pattern "https://api.example.com/users" \
  --method POST \
  --mode mock \
  --component body_param
```

#### Q: How do I match by multiple components?

**A:** Use multiple `--component` options to combine matching criteria.

**Example:**

```bash
# Match by query params AND headers
stoobly-agent setting match set \
  --pattern "https://api.example.com/search" \
  --method GET \
  --mode mock \
  --component query_param \
  --component header
```

***

### Filter Rules

#### Q: What are filter rules?

**A:** Filter rules control which requests are intercepted, allowing you to include or exclude specific URLs, methods, or patterns.

**Example:**

```bash
# Exclude analytics requests from recording
stoobly-agent setting filter set \
  --pattern "https://analytics.example.com/.*" \
  --method GET \
  --method POST \
  --mode record \
  --action exclude
```

#### Q: How do I exclude requests from interception?

**A:** Use `--action exclude` with a pattern to filter out requests.

**Example:**

```bash
# Exclude third-party tracking
stoobly-agent setting filter set \
  --pattern "https://.*google-analytics.com/.*" \
  --method GET \
  --method POST \
  --mode record \
  --mode mock \
  --action exclude
```

#### Q: How do I include only specific requests?

**A:** Use `--action include` with a pattern to whitelist requests.

**Example:**

```bash
# Only intercept API requests
stoobly-agent setting filter set \
  --pattern "https://api.example.com/.*" \
  --method GET \
  --method POST \
  --mode record \
  --action include
```

#### Q: How do I filter by HTTP method?

**A:** Use multiple `--method` options to target specific methods.

**Example:**

```bash
# Exclude OPTIONS requests
stoobly-agent setting filter set \
  --pattern ".*" \
  --method OPTIONS \
  --mode record \
  --mode mock \
  --action exclude
```

#### Q: How do I apply filter rules to specific modes?

**A:** Use multiple `--mode` options to control which intercept modes are affected.

**Example:**

```bash
# Exclude from recording only, still mock
stoobly-agent setting filter set \
  --pattern "https://cdn.example.com/.*" \
  --method GET \
  --mode record \
  --action exclude
```

***

### Project Management (Remote Features)

#### Q: How do I set the active project?

**A:** Use `config project set` with the project key (requires remote features).

**Example:**

```bash
stoobly-agent setting project set "<PROJECT-KEY>"
# Output: Project updated!
```

#### Q: How do I view the current project?

**A:** Use `config project show` to display active project details.

**Example:**

```bash
stoobly-agent setting project show
```

#### Q: How do I switch to local project mode?

**A:** Use `config project local` to use local storage instead of remote.

**Example:**

```bash
stoobly-agent setting project local
# Output: Using local project!
```

#### Q: How do I set my API key for remote features?

**A:** Use `config api-key set` with your API key.

**Example:**

```bash
stoobly-agent setting api-key set your-api-key-here
# Output: API Key updated!
```

***

### Configuration Workflows

#### Q: How do I set up environment-specific rewrite rules?

**A:** Create rewrite rules that redirect production URLs to local or staging environments.

**Example:**

```bash
# Development: Point to localhost
stoobly-agent setting rewrite set \
  --pattern "https://api.production.com/.*" \
  --method GET \
  --method POST \
  --mode mock \
  --mode test \
  --hostname localhost:8080 \
  --scheme http

# Staging: Point to staging server
stoobly-agent setting rewrite set \
  --pattern "https://api.production.com/.*" \
  --method GET \
  --method POST \
  --mode record \
  --hostname api.staging.com
```

#### Q: How do I configure request filtering for testing?

**A:** Combine filter and match rules to control which requests are tested.

**Example:**

```bash
# Exclude external services from tests
stoobly-agent setting filter set \
  --pattern "https://.*amazonaws.com/.*" \
  --method GET \
  --method POST \
  --mode test \
  --action exclude

# Match API requests precisely
stoobly-agent setting match set \
  --pattern "https://api.myapp.com/.*" \
  --method GET \
  --method POST \
  --mode test \
  --component query_param \
  --component header
```

#### Q: How do I mock with modified authentication?

**A:** Use rewrite rules to replace authentication tokens in mock mode.

**Example:**

```bash
# Replace auth tokens for mocking
stoobly-agent setting rewrite set \
  --pattern "https://api.example.com/.*" \
  --method GET \
  --method POST \
  --mode mock \
  --type header \
  --name "Authorization" \
  --value "Bearer test-token"

# Start mocking
stoobly-agent run --intercept --intercept-mode mock
```

***

### Advanced Configuration

#### Q: How do I create rules for specific projects?

**A:** Use the `--project-key` option to scope rules to a specific project.

**Example:**

```bash
# Add rewrite rule to specific project
stoobly-agent setting rewrite set \
  --pattern "https://api.example.com/.*" \
  --method GET \
  --mode mock \
  --hostname localhost \
  --project-key "<PROJECT-KEY>"
```

#### Q: How do I configure rules for microservices?

**A:** Create separate rules for each service endpoint.

**Example:**

```bash
# Auth service
stoobly-agent setting rewrite set \
  --pattern "https://auth.example.com/.*" \
  --method GET \
  --method POST \
  --mode mock \
  --hostname localhost:8001

# User service
stoobly-agent setting rewrite set \
  --pattern "https://users.example.com/.*" \
  --method GET \
  --method POST \
  --mode mock \
  --hostname localhost:8002

# Order service
stoobly-agent setting rewrite set \
  --pattern "https://orders.example.com/.*" \
  --method GET \
  --method POST \
  --mode mock \
  --hostname localhost:8003
```

***

### Troubleshooting

#### Q: How do I debug configuration issues?

**A:** Dump configuration and validate it.

**Example:**

```bash
# View configuration
stoobly-agent setting dump

# Validate configuration
stoobly-agent setting validate

# Check for specific rules
stoobly-agent setting dump | jq '.proxy.rewrite'
stoobly-agent setting dump | jq '.proxy.filter'
stoobly-agent setting dump | jq '.proxy.match'
```

#### Q: How do I reset a specific configuration section?

**A:** Currently, you can only reset all configuration. To reset specific sections, edit the config file manually or use reset and reconfigure.

**Example:**

```bash
# Backup current config
stoobly-agent setting dump --save-to-file

# Reset to defaults
stoobly-agent setting reset

# Reconfigure specific sections
stoobly-agent setting rewrite set ...
```

#### Q: How do I check if my rewrite rules are working?

**A:** Use increased logging and flow detail to see rule application.

**Example:**

```bash
# Start with debug logging
stoobly-agent run --log-level debug --flow-detail 4 --intercept --intercept-mode mock

# Make request and check logs for rewrite application
```

***

### Quick Reference

#### Q: What are the most common config commands?

**A:** Here's a quick reference of frequently used commands:

**Example:**

```bash
# View configuration
stoobly-agent setting dump
stoobly-agent setting dump --dir
stoobly-agent setting dump --save-to-file

# Reset configuration
stoobly-agent setting reset
stoobly-agent setting validate

# Manage scenarios
stoobly-agent setting scenario set "<SCENARIO-KEY>"
stoobly-agent setting scenario show
stoobly-agent setting scenario clear

# Rewrite rules
stoobly-agent setting rewrite set \
  --pattern "URL_PATTERN" \
  --method GET --method POST \
  --mode mock --mode record \
  --hostname new-host.com

# Match rules
stoobly-agent setting match set \
  --pattern "URL_PATTERN" \
  --method GET \
  --mode mock \
  --component query_param --component header

# Filter rules
stoobly-agent setting filter set \
  --pattern "URL_PATTERN" \
  --method GET \
  --mode record \
  --action exclude

# Project management (remote features)
stoobly-agent setting api-key set "<API-KEY>"
stoobly-agent setting project set "<PROJECT-KEY>"
stoobly-agent setting project show
stoobly-agent setting project local
```

***

### Best Practices

#### Q: How should I organize my configuration?

**A:** Use specific patterns for different services and environments.

**Example:**

```bash
# Service-specific patterns
stoobly-agent setting rewrite set --pattern "https://api.myapp.com/.*" ...
stoobly-agent setting rewrite set --pattern "https://auth.myapp.com/.*" ...

# Environment-specific rules
stoobly-agent setting rewrite set --mode mock --hostname localhost ...
stoobly-agent setting rewrite set --mode record --hostname staging.com ...
```

#### Q: When should I use filter rules vs match rules?

**A:** Use filter rules to control what gets intercepted, match rules to control how requests are matched to responses.

**Example:**

```bash
# Filter: Exclude from interception
stoobly-agent setting filter set --pattern "https://cdn..*" --action exclude

# Match: Control matching precision
stoobly-agent setting match set --pattern "https://api..*" --component query_param
```


# Installation

## How do I install stoobly-agent?

### Option 1: Install with pipx (recommended)

**Prerequisites:**

* Python 3.12, 3.13, or 3.14

**Install pipx:**

macOS:

```bash
brew install pipx
pipx ensurepath
source ~/.bashrc
```

Linux:

```bash
python3 -m pip install --user pipx
python3 -m pipx ensurepath
source ~/.bashrc
```

**Install stoobly-agent:**

```bash
pipx install stoobly-agent --python python3
```

**Verify:**

```bash
stoobly-agent --help
```

More details: [Installation with pipx](https://docs.stoobly.com/getting-started/install-and-run/installation-with-pipx)

***

### Option 2: Install with Docker

**Prerequisites:**

* Docker installed ([official instructions](https://docs.docker.com/engine/install))

**Pull the image:**

```bash
docker pull stoobly/agent
```

**Verify:**

```bash
docker run \
    -v ~/.stoobly:/home/stoobly/.stoobly \
    stoobly/agent \
    stoobly-agent --help
```

More details: [Installation with Docker](https://docs.stoobly.com/getting-started/install-and-run/installation-with-docker)

***

## How do I update stoobly-agent?

### With pipx:

```bash
pipx upgrade stoobly-agent
```

### With Docker:

```bash
docker pull stoobly/agent
```

***

## What Python versions are supported?

Python 3.12, 3.13, and 3.14 are officially supported.

If you need to install a specific Python version, use [pyenv](https://github.com/pyenv/pyenv):

```bash
pyenv install 3.13.0
pyenv local 3.13.0
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv init -)"
```

***

## How do I verify stoobly-agent is installed?

### With pipx:

```bash
stoobly-agent --help
```

### With Docker:

```bash
docker run \
    -v ~/.stoobly:/home/stoobly/.stoobly \
    stoobly/agent \
    stoobly-agent --help
```

***

## Next Steps

After installation:

* **API Mocking:** [How to Record Requests](https://docs.stoobly.com/guides/how-to-record-requests/)
* **E2E Testing:** [How to Integrate E2E Testing](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/)


# Intercept

## Stoobly Intercept CLI - Questions & Answers

The intercept CLI allows you to dynamically configure the stoobly-agent **after** it's already running with `stoobly-agent run`. This enables you to change modes, policies, and strategies without restarting the agent.

***

### Getting Started with Intercept

#### Q: What is the intercept feature?

**A:** Intercept is a feature that allows the stoobly-agent proxy to capture, modify, and control HTTP requests in real-time. You can enable/disable it and configure its behavior while the agent is running.

**Example:**

```bash
# Start the agent
stoobly-agent run

# In another terminal, enable intercept
stoobly-agent intercept enable
```

#### Q: How do I check the current intercept configuration?

**A:** Use the `intercept show` command to display the current mode, policy, strategy, and status.

**Example:**

```bash
stoobly-agent intercept show
# Output: Mock with policy: 'found', strategy: 'None', enabled
```

***

### Enabling and Disabling Intercept

#### Q: How do I enable intercept mode?

**A:** Use `stoobly-agent intercept enable` to activate request interception on a running agent.

**Example:**

```bash
# Start agent first
stoobly-agent run

# In another terminal, enable intercept
stoobly-agent intercept enable
# Output: Intercept enabled!
```

#### Q: How do I disable intercept mode?

**A:** Use `stoobly-agent intercept disable` to deactivate request interception without stopping the agent.

**Example:**

```bash
stoobly-agent intercept disable
# Output: Intercept disabled!
```

#### Q: Can I enable intercept when starting the agent?

**A:** Yes, use the `--intercept` flag when running the agent to enable it at startup.

**Example:**

```bash
stoobly-agent run --intercept --intercept-mode mock
```

***

### Configuring Intercept Modes

#### Q: What intercept modes are available?

**A:** There are four intercept modes: `mock`, `record`, `replay`, and `test` (test requires remote features enabled).

**Example:**

```bash
# View available modes
stoobly-agent intercept set --help

# Set to mock mode
stoobly-agent intercept set --mode mock

# Set to record mode
stoobly-agent intercept set --mode record

# Set to replay mode
stoobly-agent intercept set --mode replay

# Set to test mode (if remote features enabled)
stoobly-agent intercept set --mode test
```

#### Q: How do I switch from record mode to mock mode?

**A:** Use the `intercept configure --mode` command to change modes while the agent is running.

**Example:**

```bash
# Currently in record mode, switch to mock
stoobly-agent intercept set --mode mock
# Output: Updating intercept mode to mock
```

#### Q: What happens when I change the intercept mode?

**A:** When you change modes, intercept is automatically disabled, the mode is updated, and you need to re-enable intercept for the new mode to take effect.

**Example:**

```bash
# Change mode (intercept gets disabled)
stoobly-agent intercept set --mode record

# Re-enable intercept
stoobly-agent intercept enable
```

***

### Mock Mode Configuration

#### Q: What is mock mode?

**A:** Mock mode serves previously recorded responses instead of making real HTTP requests, useful for testing without external dependencies.

**Example:**

```bash
stoobly-agent intercept set --mode mock
stoobly-agent intercept enable
```

#### Q: What policies are available for mock mode?

**A:** Mock mode supports two policies: `all` (mock all requests) and `found` (only mock requests with recorded responses).

**Example:**

```bash
# Mock all requests
stoobly-agent intercept set --mode mock --policy all

# Only mock requests that have recorded responses
stoobly-agent intercept set --mode mock --policy found
```

#### Q: How do I configure mock mode to only serve recorded responses?

**A:** Set the mock policy to `found` to only mock requests that have matching recorded responses.

**Example:**

```bash
stoobly-agent intercept set --mode mock --policy found
stoobly-agent intercept enable
```

***

### Record Mode Configuration

#### Q: What is record mode?

**A:** Record mode captures HTTP requests and responses as they pass through the proxy, storing them for later replay or mocking.

**Example:**

```bash
stoobly-agent intercept set --mode record
stoobly-agent intercept enable
```

#### Q: What policies are available for record mode?

**A:** Record mode supports four policies: `all`, `api`, `found`, and `not_found`.

**Example:**

```bash
# Record all requests
stoobly-agent intercept set --mode record --policy all

# Record only API requests
stoobly-agent intercept set --mode record --policy api

# Record only requests with existing records
stoobly-agent intercept set --mode record --policy found

# Record only new requests (not previously recorded)
stoobly-agent intercept set --mode record --policy not_found
```

#### Q: What recording strategies are available?

**A:** Record mode supports two strategies: `full` (capture complete request/response) and `minimal` (capture only essential data).

**Example:**

```bash
# Full recording (complete data)
stoobly-agent intercept set --mode record --strategy full

# Minimal recording (essential data only)
stoobly-agent intercept set --mode record --strategy minimal
```

#### Q: What recording orders are available?

**A:** Record mode supports two orders: `append` (add new records) and `overwrite` (replace existing records).

**Example:**

```bash
# Append new recordings
stoobly-agent intercept set --mode record --order append

# Overwrite existing recordings
stoobly-agent intercept set --mode record --order overwrite
```

#### Q: How do I configure record mode to only capture new requests?

**A:** Set the record policy to `not_found` to only record requests that haven't been captured before.

**Example:**

```bash
stoobly-agent intercept set --mode record --policy not_found
stoobly-agent intercept enable
```

#### Q: How do I configure record mode to overwrite existing recordings?

**A:** Set the record order to `overwrite` to replace existing recordings with new captures.

**Example:**

```bash
stoobly-agent intercept set --mode record --order overwrite
stoobly-agent intercept enable
```

***

### Replay Mode Configuration

#### Q: What is replay mode?

**A:** Replay mode re-executes previously recorded requests, useful for testing and debugging.

**Example:**

```bash
stoobly-agent intercept set --mode replay
stoobly-agent intercept enable
```

#### Q: What policies are available for replay mode?

**A:** Replay mode currently supports the `all` policy to replay all intercepted requests.

**Example:**

```bash
stoobly-agent intercept set --mode replay --policy all
stoobly-agent intercept enable
```

***

### Test Mode Configuration

#### Q: What is test mode?

**A:** Test mode validates responses against expected results, useful for automated testing and contract validation.

**Example:**

```bash
stoobly-agent intercept set --mode test
stoobly-agent intercept enable
```

#### Q: What policies are available for test mode?

**A:** Test mode supports the `found` policy to only test requests with recorded responses.

**Example:**

```bash
stoobly-agent intercept set --mode test --policy found
stoobly-agent intercept enable
```

#### Q: What test strategies are available?

**A:** Test mode supports four strategies: `contract`, `custom`, `diff`, and `fuzzy`.

**Example:**

```bash
# Contract testing (validate against schema)
stoobly-agent intercept set --mode test --strategy contract

# Custom testing (use custom validation logic)
stoobly-agent intercept set --mode test --strategy custom

# Diff testing (compare exact responses)
stoobly-agent intercept set --mode test --strategy diff

# Fuzzy testing (allow minor variations)
stoobly-agent intercept set --mode test --strategy fuzzy
```

#### Q: How do I set up contract testing?

**A:** Configure test mode with the contract strategy to validate responses against defined schemas.

**Example:**

```bash
stoobly-agent intercept set --mode test --strategy contract --policy found
stoobly-agent intercept enable
```

***

### Advanced Configuration

#### Q: Can I configure multiple options at once?

**A:** Yes, you can combine mode, policy, strategy, and order options in a single command.

**Example:**

```bash
# Configure record mode with all options
stoobly-agent intercept set --mode record --policy not_found --strategy full --order append

# Configure test mode with strategy and policy
stoobly-agent intercept set --mode test --strategy diff --policy found
```

#### Q: How do I configure intercept for a specific scenario?

**A:** First configure the mode and settings, then enable intercept. Use lifecycle hooks for scenario-specific logic.

**Example:**

```bash
# Configure for recording a specific API
stoobly-agent intercept set --mode record --policy api --strategy full
stoobly-agent intercept enable

# Run your tests/requests
# ...

# Switch to mock mode for testing
stoobly-agent intercept set --mode mock --policy found
stoobly-agent intercept enable
```

***

### Workflow Examples

#### Q: How do I set up a record-then-mock workflow?

**A:** Start by recording requests, then switch to mock mode to replay them. Optionally create a scenario before recording to organize your requests.

**Example:**

```bash
# Step 1: Start the agent
stoobly-agent run

# Step 2 (Optional): Create a scenario to organize requests
stoobly-agent scenario create "My User Flow"
# Output: Created scenario with key: <SCENARIO-KEY>

# Step 3: Configure and enable recording
stoobly-agent intercept set --mode record --policy all --strategy full
stoobly-agent intercept enable

# Step 4: Make requests (they get recorded)
# ... perform your API calls ...

# Step 5: Switch to mock mode
stoobly-agent intercept set --mode mock --policy found
stoobly-agent intercept enable

# Step 6: Run tests against mocked responses
# ... run your test suite ...
```

#### Q: How do I set up continuous recording with overwrite?

**A:** Configure record mode with overwrite order to always capture the latest responses.

**Example:**

```bash
stoobly-agent run --intercept --intercept-mode record

# In another terminal
stoobly-agent intercept set --mode record --order overwrite --policy all
```

#### Q: How do I set up automated testing with validation?

**A:** Configure test mode with your preferred validation strategy.

**Example:**

```bash
# Start agent
stoobly-agent run

# Configure test mode with diff strategy
stoobly-agent intercept set --mode test --strategy diff --policy found
stoobly-agent intercept enable

# Run your test suite - responses will be validated automatically
```

***

### Troubleshooting

#### Q: What happens if I try to set an invalid policy for a mode?

**A:** The command will fail with an error message showing valid policies for that mode.

**Example:**

```bash
# This will fail if policy is invalid for the mode
stoobly-agent intercept set --mode mock --policy not_found
# Output: Error: Valid policies for mock are ['all', 'found']
```

#### Q: Why does intercept get disabled when I change modes?

**A:** Changing modes requires reconfiguring the proxy behavior, so intercept is automatically disabled. You need to re-enable it after changing modes.

**Example:**

```bash
# Change mode (intercept disabled automatically)
stoobly-agent intercept set --mode record

# Check status
stoobly-agent intercept show
# Output: Record with policy: 'all', strategy: 'full', disabled

# Re-enable intercept
stoobly-agent intercept enable
```

#### Q: How do I verify my intercept configuration is working?

**A:** Use `intercept show` to check the current configuration and status.

**Example:**

```bash
stoobly-agent intercept show
# Output: Mock with policy: 'found', strategy: 'None', enabled
```

**Technique 2 — Inspect response headers with curl:**

Stoobly injects `x-stoobly-*` headers into responses it serves. Re-run your request with `-v` (verbose) to see them:

```bash
curl -v --proxy http://localhost:8080 https://your-api.example.com/path
```

Look for a header like `x-stoobly-mock: 1` in the response. If it's present, the response came from Stoobly — not the real service. This is the quickest way to confirm end-to-end that the proxy is intercepting and serving your request.

**Technique 3 — Edit a recorded response (most definitive):**

Open the Stoobly UI at `http://localhost:4200`, find the recorded request, edit its response body to something obviously fake, then re-run your curl. If you receive the fake value, Stoobly owns the response.

#### Q: Can I configure intercept before enabling it?

**A:** Yes, you can configure all settings first, then enable intercept to apply them.

**Example:**

```bash
# Configure first
stoobly-agent intercept set --mode record --policy all --strategy full --order append

# Then enable
stoobly-agent intercept enable
```

***

### Quick Reference

#### Q: What's a quick reference for common intercept commands?

**A:** Here are the most frequently used intercept commands:

**Example:**

```bash
# View current configuration
stoobly-agent intercept show

# Enable/disable intercept
stoobly-agent intercept enable
stoobly-agent intercept disable

# Switch modes
stoobly-agent intercept set --mode mock
stoobly-agent intercept set --mode record
stoobly-agent intercept set --mode replay
stoobly-agent intercept set --mode test

# Configure record mode
stoobly-agent intercept set --mode record --policy all --strategy full --order append

# Configure mock mode
stoobly-agent intercept set --mode mock --policy found

# Configure test mode
stoobly-agent intercept set --mode test --strategy diff --policy found

# Complete workflow
stoobly-agent intercept set --mode record --policy all
stoobly-agent intercept enable
# ... make requests ...
stoobly-agent intercept set --mode mock --policy found
stoobly-agent intercept enable
# ... run tests ...
```

***

### Integration with Other Features

#### Q: How does intercept work with scenarios?

**A:** Intercept can be configured to work with specific scenarios for organized request management.

**Example:**

```bash
# Record requests to a scenario
stoobly-agent run --intercept --intercept-mode record --scenario-key "<SCENARIO-KEY>"

# Configure intercept for the scenario
stoobly-agent intercept set --mode record --policy all
```

#### Q: Can I use intercept with lifecycle hooks?

**A:** Yes, intercept works seamlessly with lifecycle hooks for custom request/response processing.

**Example:**

```bash
# Start with lifecycle hooks
stoobly-agent run --lifecycle-hooks-path ./hooks.py

# Configure intercept
stoobly-agent intercept set --mode mock --policy found
stoobly-agent intercept enable
```

```

This comprehensive Q&A guide covers all aspects of the intercept CLI, providing users with clear examples for configuring and managing request interception dynamically while the agent is running.
```


# Request

## Stoobly Request CLI - Questions & Answers

The request CLI enables you to manage recorded HTTP requests, replay them, test responses, and work with request/response data. These commands help you work with individual requests outside of scenarios.

***

### Listing Requests

#### Q: How do I view all recorded requests?

**A:** Use `request list` to display all recorded requests with pagination.

**Example:**

```bash
stoobly-agent request list
```

#### Q: How do I paginate through requests?

**A:** Use the `--page` and `--size` options to control pagination.

**Example:**

```bash
# Show first 10 requests (default)
stoobly-agent request list --page 0 --size 10

# Show next 20 requests
stoobly-agent request list --page 1 --size 20

# Show 50 requests per page
stoobly-agent request list --page 0 --size 50
```

#### Q: How do I filter requests by scenario?

**A:** Use the `--scenario-key` option to show only requests from a specific scenario.

**Example:**

```bash
stoobly-agent request list --scenario-key "<SCENARIO-KEY>"
```

#### Q: How do I search for specific requests?

**A:** Use the `--search` option to filter requests by URL path or other criteria.

**Example:**

```bash
# Search by path
stoobly-agent request list --search "/api/users"

# Search by domain
stoobly-agent request list --search "example.com"
```

#### Q: How do I sort requests?

**A:** Use `--sort-by` and `--sort-order` options to control sorting.

**Example:**

```bash
# Sort by creation date (newest first, default)
stoobly-agent request list --sort-by created_at --sort-order desc

# Sort by creation date (oldest first)
stoobly-agent request list --sort-by created_at --sort-order asc

# Sort by path
stoobly-agent request list --sort-by path --sort-order asc
```

#### Q: How do I format the request list output?

**A:** Use the `--format` option to change output format (table, json, csv).

**Example:**

```bash
# Table format (default)
stoobly-agent request list --format table

# JSON format
stoobly-agent request list --format json

# CSV format
stoobly-agent request list --format csv
```

#### Q: How do I select specific columns to display?

**A:** Use the `--select` option to choose which columns to show.

**Example:**

```bash
# Show only specific columns
stoobly-agent request list --select id --select path --select method

# Show multiple columns
stoobly-agent request list --select id --select path --select method --select created_at
```

#### Q: How do I hide column headers?

**A:** Use the `--without-headers` flag to disable column headers.

**Example:**

```bash
stoobly-agent request list --without-headers
```

#### Q: How do I export requests to a file?

**A:** Use format options and shell redirection to export requests.

**Example:**

```bash
# Export as JSON
stoobly-agent request list --format json > requests.json

# Export as CSV
stoobly-agent request list --format csv > requests.csv

# Export specific scenario
stoobly-agent request list --scenario-key "<SCENARIO-KEY>" --format json > scenario-requests.json
```

***

### Replaying Requests

#### Q: How do I replay a recorded request?

**A:** Use `request replay` with the request key to re-execute a recorded request.

**Example:**

```bash
stoobly-agent request replay "<REQUEST-KEY>"
```

#### Q: How do I replay a request to a different host?

**A:** Use the `--host` option to override the request host.

**Example:**

```bash
# Replay to localhost
stoobly-agent request replay "<REQUEST-KEY>" --host localhost:8080

# Replay to staging
stoobly-agent request replay "<REQUEST-KEY>" --host staging.example.com
```

#### Q: How do I replay a request with a different scheme (HTTP/HTTPS)?

**A:** Use the `--scheme` option to change the protocol.

**Example:**

```bash
# Force HTTP
stoobly-agent request replay "<REQUEST-KEY>" --scheme http

# Force HTTPS
stoobly-agent request replay "<REQUEST-KEY>" --scheme https
```

#### Q: How do I replay a request and record the new response?

**A:** Use the `--record` flag to capture the replayed response.

**Example:**

```bash
stoobly-agent request replay "<REQUEST-KEY>" --record
```

#### Q: How do I replay a request and overwrite the existing response?

**A:** Use the `--overwrite` flag to replace the stored response (local mode only).

**Example:**

```bash
stoobly-agent request replay "<REQUEST-KEY>" --overwrite
```

#### Q: How do I replay a request to a specific scenario?

**A:** Use the `--scenario-key` option to record the replay into a scenario.

**Example:**

```bash
stoobly-agent request replay "<REQUEST-KEY>" --record --scenario-key "<SCENARIO-KEY>"
```

#### Q: How do I format the replay response output?

**A:** Use the `--format` option to control response display.

**Example:**

```bash
# Body only
stoobly-agent request replay "<REQUEST-KEY>" --format body

# Full JSON with metadata
stoobly-agent request replay "<REQUEST-KEY>" --format json
```

#### Q: How do I replay a request with custom lifecycle hooks?

**A:** Use the `--lifecycle-hooks-path` option to apply custom processing.

**Example:**

```bash
stoobly-agent request replay "<REQUEST-KEY>" --lifecycle-hooks-path ./hooks.py
```

#### Q: How do I increase logging verbosity when replaying?

**A:** Use the `--log-level` option to see more details.

**Example:**

```bash
# Debug level (most verbose)
stoobly-agent request replay "<REQUEST-KEY>" --log-level debug

# Info level
stoobly-agent request replay "<REQUEST-KEY>" --log-level info
```

***

### Working with Aliases (Remote Features)

#### Q: How do I replay a request with assigned alias values?

**A:** Use the `--assign` option to set alias values before replay.

**Example:**

```bash
# Assign single alias
stoobly-agent request replay "<REQUEST-KEY>" --assign userId=12345

# Assign multiple aliases
stoobly-agent request replay "<REQUEST-KEY>" --assign userId=12345 --assign token=abcde12345
```

#### Q: How do I validate alias values during replay?

**A:** Use the `--validate` option to specify validation rules for aliases.

**Example:**

```bash
# Validate userId is an integer
stoobly-agent request replay "<REQUEST-KEY>" --validate "userId=?int"

# Validate multiple aliases
stoobly-agent request replay "<REQUEST-KEY>" --validate "userId=?int" --validate "email=?string"
```

#### Q: How do I control alias resolution strategy?

**A:** Use the `--alias-resolve-strategy` option to specify how aliases are resolved.

**Example:**

```bash
# No alias resolution (default)
stoobly-agent request replay "<REQUEST-KEY>" --alias-resolve-strategy none

# First-in-first-out resolution
stoobly-agent request replay "<REQUEST-KEY>" --alias-resolve-strategy fifo

# Last-in-first-out resolution
stoobly-agent request replay "<REQUEST-KEY>" --alias-resolve-strategy lifo
```

#### Q: How do I repeat a request replay for each alias value?

**A:** Use the `--group-by` option to iterate over alias values.

**Example:**

```bash
# Replay once for each userId value
stoobly-agent request replay "<REQUEST-KEY>" --group-by userId

# Results in multiple replays with different userId values
```

#### Q: How do I use an existing trace for replay?

**A:** Use the `--trace-id` option to leverage a previous trace.

**Example:**

```bash
stoobly-agent request replay "<REQUEST-KEY>" --trace-id "<TRACE-ID>"
```

***

### Snapshots and Version Control

#### Q: How do I create a snapshot of a request?

**A:** Use `request snapshot` to create a committable file for the request (local mode only).

**Example:**

```bash
stoobly-agent request snapshot "<REQUEST-KEY>"
```

#### Q: How do I delete a request snapshot?

**A:** Use the `--action delete` option with snapshot command.

**Example:**

```bash
stoobly-agent request snapshot "<REQUEST-KEY>" --action delete
```

#### Q: How do I snapshot a request with decoded response body?

**A:** Use the `--decode` flag to decode the response body in the snapshot.

**Example:**

```bash
stoobly-agent request snapshot "<REQUEST-KEY>" --decode
```

#### Q: How do I reset a request to its snapshot state?

**A:** Use `request reset` to restore a request from its snapshot.

**Example:**

```bash
stoobly-agent request reset "<REQUEST-KEY>"
```

#### Q: How do I force delete when resetting a request?

**A:** Use the `--force` flag to hard delete the request data.

**Example:**

```bash
stoobly-agent request reset "<REQUEST-KEY>" --force
```

#### Q: How do I share requests with my team via git?

**A:** Create snapshots and commit them to version control.

**Example:**

```bash
# Create snapshot
stoobly-agent request snapshot "<REQUEST-KEY>"

# Commit to git
git add .stoobly/snapshots/
git commit -m "Add request snapshot"
git push

# Team member pulls and uses
git pull
stoobly-agent request reset "<REQUEST-KEY>"  # Restore from snapshot
stoobly-agent request replay "<REQUEST-KEY>"  # Use the request
```

***

### Updating Requests

The following snapshot-based workflows are the **recommended approach** when updating single requests or requests that belong to an API endpoint.

#### Q: How do I update a single request?

**A:** Use the snapshot workflow to edit a request's data directly by modifying its snapshot file.

**Steps:**

1. Find the request key for the request you want to update:

```bash
stoobly-agent request list --search "/api/users"
```

2. Snapshot it using `stoobly-agent request snapshot "<REQUEST-KEY>"`. The output of the command is the snapshot file path:

```bash
stoobly-agent request snapshot "<REQUEST-KEY>"
```

3. Update the snapshot file. The format of the file is a raw HTTP request and response separated by a delimiter.
4. Run `stoobly-agent snapshot apply` to apply the updated snapshot to the database:

```bash
stoobly-agent snapshot apply
```

More details: [Editing with Snapshots](https://docs.stoobly.com/guides/how-to-update-requests/editing-with-snapshots), [Snapshot FAQ](https://docs.stoobly.com/faq/snapshot)

#### Q: How do I update all requests matching an API endpoint whose contract has changed?

**A:** When an API endpoint's request or response contract changes, use the snapshot workflow to update all matching requests in bulk.

**Steps:**

1. Find all request keys matching the endpoint pattern:

```bash
stoobly-agent request list --search "<PATTERN>" --select key --without-headers
```

Where `<PATTERN>` uses SQLite search syntax. For endpoints where a path segment is an ID (e.g., `/users/1`), the search pattern should be `/users/%`. The output will be request keys separated by newlines.

2. For each key in the search results, snapshot it using `stoobly-agent request snapshot "<REQUEST-KEY>"`. The output of the command is a snapshot file path for each key:

```bash
stoobly-agent request list --search "<PATTERN>" --select key --without-headers | while read key; do
  stoobly-agent request snapshot "$key"
done
```

3. For each path in the search results, update the snapshot file. The format of the files is raw HTTP requests and responses separated by a delimiter.
4. Run `stoobly-agent snapshot apply` to apply all updated snapshots to the database:

```bash
stoobly-agent snapshot apply
```

More details: [Editing with Snapshots](https://docs.stoobly.com/guides/how-to-update-requests/editing-with-snapshots), [Snapshot FAQ](https://docs.stoobly.com/faq/snapshot)

If you need to **update all requests within a scenario**, use the scenario-specific workflows described in the [Scenario FAQ](https://docs.stoobly.com/faq/scenario) and the [How to Update Scenarios](https://docs.stoobly.com/guides/how-to-update-requests/how-to-update-scenarios/) guide.

***

### Managing Request Responses

#### Q: How do I view the response for a recorded request?

**A:** Use `request response show` to retrieve the stored response.

**Example:**

```bash
stoobly-agent request response show "<REQUEST-KEY>"
```

#### Q: How do I query specific properties in a response?

**A:** Use `request response query` with a query expression.

**Example:**

```bash
# Query JSON path
stoobly-agent request response query "<REQUEST-KEY>" --query "$.data.users[0].name"

# Query nested property
stoobly-agent request response query "<REQUEST-KEY>" --query "$.response.body"
```

#### Q: How do I extract data from a response for scripting?

**A:** Combine response query with shell processing.

**Example:**

```bash
# Extract user ID
userId=$(stoobly-agent request response query "<REQUEST-KEY>" --query "$.data.id")

# Use in another command
echo "User ID: $userId"

# Extract array of values
stoobly-agent request response query "<REQUEST-KEY>" --query "$.data.users[*].email"
```

***

### Deleting Requests

#### Q: How do I delete a recorded request?

**A:** Use `request delete` with the request key.

**Example:**

```bash
stoobly-agent request delete "<REQUEST-KEY>"
```

#### Q: How do I delete multiple requests?

**A:** Use a loop or script to delete requests in bulk.

**Example:**

```bash
# Delete multiple specific requests
stoobly-agent request delete "<REQUEST-KEY-1>"
stoobly-agent request delete "<REQUEST-KEY-2>"
stoobly-agent request delete "<REQUEST-KEY-3>"

# Delete all requests from a scenario (scripted)
for key in $(stoobly-agent request list --scenario-key "<SCENARIO-KEY>" --format json | jq -r '.[].id'); do
  stoobly-agent request delete $key
done
```

***

### Managing Intercepted Request Logs

#### Q: How do I view the intercepted requests log?

**A:** Use `request logs list` to display all logged intercepted requests. Use `-f` to stream logs in real time, or filter by method, URL, status code, log level, and more.

**Examples:**

```bash
# List all intercepted request log entries
stoobly-agent request logs list

# Follow logs in real time (-f / --follow, Ctrl-C to stop)
stoobly-agent request logs list --follow

# Filter by HTTP method
stoobly-agent request logs list --method get

# Filter by URL substring
stoobly-agent request logs list --url /api/users

# Filter by HTTP status code
stoobly-agent request logs list --status-code 500

# Filter by log level
stoobly-agent request logs list --level error

# Filter by log message
stoobly-agent request logs list --message "Mock failure"

# Filter by scenario name
stoobly-agent request logs list --scenario-name my-scenario

# Output as JSON
stoobly-agent request logs list --format json

# Select specific columns
stoobly-agent request logs list --select method,url,status-code

# Combine filters with follow
stoobly-agent request logs list --follow --level error --method post
```

#### Q: How do I clear the intercepted requests log?

**A:** Use `request logs delete` to truncate the log file.

**Example:**

```bash
stoobly-agent request logs delete
```

#### Q: How do I enable request logging?

**A:** Use the `--request-log-enable` flag when starting the agent.

**Example:**

```bash
# Enable request logging
stoobly-agent run --request-log-enable

# View logs in another terminal
stoobly-agent request logs list
```

#### Q: How do I set the log level for intercepted requests?

**A:** Use the `--request-log-level` option when starting the agent.

**Example:**

```bash
stoobly-agent run --request-log-enable --request-log-level debug
```

#### Q: How do I prevent log truncation on startup?

**A:** Set `--request-log-truncate` to false when starting the agent.

**Example:**

```bash
# Don't truncate log on startup
stoobly-agent run --request-log-enable --request-log-truncate=false
```

***

### Advanced Request Operations

#### Q: How do I replay multiple requests in sequence?

**A:** Use a loop or script to replay requests sequentially.

**Example:**

```bash
# Replay multiple requests
for key in "<REQUEST-KEY-1>" "<REQUEST-KEY-2>" "<REQUEST-KEY-3>"; do
  stoobly-agent request replay $key
done

# Replay all requests in a scenario
for key in $(stoobly-agent request list --scenario-key "<SCENARIO-KEY>" --format json | jq -r '.[].id'); do
  stoobly-agent request replay $key --record
done
```

#### Q: How do I compare requests before and after changes?

**A:** Replay and record, then use snapshots to track changes.

**Example:**

```bash
# Create initial snapshot
stoobly-agent request snapshot "<REQUEST-KEY>"

# Make changes and replay
stoobly-agent request replay "<REQUEST-KEY>" --overwrite

# Compare with snapshot
git diff .stoobly/snapshots/requests/<REQUEST-KEY>.json
```

#### Q: How do I chain requests with dependencies?

**A:** Use aliases and assign values from one request to another.

**Example:**

```bash
# First request creates a user, extract ID
userId=$(stoobly-agent request response query "<REQUEST-KEY-1>" --query "$.data.id")

# Second request uses that ID
stoobly-agent request replay "<REQUEST-KEY-2>" --assign "userId=$userId"
```

#### Q: How do I replay a request with custom headers?

**A:** Use lifecycle hooks to modify request headers before replay.

**Example:**

```bash
# Create hooks.py with custom header logic
cat > hooks.py << 'EOF'
def before_request(context):
    context.request.headers['X-Custom-Header'] = 'custom-value'
    return context
EOF

# Replay with hooks
stoobly-agent request replay "<REQUEST-KEY>" --lifecycle-hooks-path ./hooks.py
```

***

### Filtering and Formatting

#### Q: How do I create a custom report of requests?

**A:** Use format options and select specific fields for custom reporting.

**Example:**

```bash
# Custom CSV report
stoobly-agent request list \
  --select id --select method --select path --select created_at \
  --format csv \
  --without-headers > requests-report.csv

# JSON report with filtering
stoobly-agent request list \
  --scenario-key "<SCENARIO-KEY>" \
  --sort-by created_at \
  --sort-order asc \
  --format json > scenario-report.json
```

#### Q: How do I find requests by method?

**A:** Use the search option or filter the output.

**Example:**

```bash
# Search for POST requests
stoobly-agent request list --format json | jq '.[] | select(.method=="POST")'

# Search for GET requests to specific path
stoobly-agent request list --search "/api/users" --format json | jq '.[] | select(.method=="GET")'
```

***

### Working with Remote Projects

#### Q: How do I list requests from a remote project?

**A:** Use the `--project-key` option to specify the remote project (remote features).

**Example:**

```bash
stoobly-agent request list --project-key "<PROJECT-KEY>"
```

#### Q: How do I test against a remote project's endpoint definitions?

**A:** Use the `--remote-project-key` option when testing.

**Example:**

```bash
stoobly-agent request test "<REQUEST-KEY>" --remote-project-key "<PROJECT-KEY>"
```

***

### Troubleshooting

#### Q: How do I debug a failing request replay?

**A:** Increase log level and use verbose output.

**Example:**

```bash
stoobly-agent request replay "<REQUEST-KEY>" --log-level debug
```

#### Q: How do I see the full request and response details?

**A:** Use JSON format and query specific fields.

**Example:**

```bash
# Get full response
stoobly-agent request response show "<REQUEST-KEY>" --format json

# Query specific parts
stoobly-agent request response query "<REQUEST-KEY>" --query "$.headers"
stoobly-agent request response query "<REQUEST-KEY>" --query "$.body"
```

#### Q: What do I do if a request key is not found?

**A:** List all requests to find the correct key.

**Example:**

```bash
# List all requests to find the key
stoobly-agent request list

# Search for specific request
stoobly-agent request list --search "/api/endpoint"
```

***

### Quick Reference

#### Q: What are the most common request commands?

**A:** Here's a quick reference of frequently used commands:

**Example:**

```bash
# List requests
stoobly-agent request list
stoobly-agent request list --scenario-key "<SCENARIO-KEY>"
stoobly-agent request list --search "/api/users"

# Replay requests
stoobly-agent request replay "<REQUEST-KEY>"
stoobly-agent request replay "<REQUEST-KEY>" --host localhost:8080
stoobly-agent request replay "<REQUEST-KEY>" --record

# Test requests
stoobly-agent request test "<REQUEST-KEY>"
stoobly-agent request test "<REQUEST-KEY>" --strategy diff
stoobly-agent request test "<REQUEST-KEY>" --strategy contract

# Snapshots
stoobly-agent request snapshot "<REQUEST-KEY>"
stoobly-agent request reset "<REQUEST-KEY>"

# View responses
stoobly-agent request response show "<REQUEST-KEY>"
stoobly-agent request response query "<REQUEST-KEY>" --query "$.data"

# Delete requests
stoobly-agent request delete "<REQUEST-KEY>"

# Manage logs
stoobly-agent request logs list
stoobly-agent request logs delete
```

***


# Run

## Stoobly Main CLI Commands - Questions & Answers

The main CLI provides core commands for running the Stoobly agent, initializing contexts, and performing quick record/mock operations without starting the full proxy server.

***

### Getting Started

#### Q: How do I check the Stoobly agent version?

**A:** Use the `--version` flag to display the installed version.

**Example:**

```bash
stoobly-agent --version
```

#### Q: How do I get help for any command?

**A:** Use `--help` or `-h` after any command to see detailed usage information.

**Example:**

```bash
# Main help
stoobly-agent --help

# Command-specific help
stoobly-agent run --help
stoobly-agent record --help
stoobly-agent mock --help
```

***

### Initializing Stoobly

#### Q: How do I initialize a new Stoobly context?

**A:** Use the `init` command to create a new `.stoobly` directory with necessary configuration files.

**Example:**

```bash
# Initialize in current directory
stoobly-agent init

# Creates: .stoobly/ directory with database and configuration
```

#### Q: What does init create?

**A:** The init command creates the `.stoobly` directory structure including database, configuration files, and necessary subdirectories.

**Example:**

```bash
stoobly-agent init

# Created structure:
# .stoobly/
# ├── db/              # Database files
# ├── ca_certs/        # CA certificates
# ├── certs/           # SSL certificates
# ├── logs/            # Log files
# └── config.yml       # Configuration
```

#### Q: When should I run init?

**A:** Run init when setting up Stoobly in a new project directory or when you want to create a fresh Stoobly context.

**Example:**

```bash
# New project setup
mkdir my-project
cd my-project
stoobly-agent init
```

***

### Running the Agent

#### Q: How do I start Stoobly with both proxy and UI?

**A:** Use the `run` command without any flags to start both the proxy server and web UI.

**Example:**

```bash
stoobly-agent run

# Proxy: http://localhost:8080
# UI: http://localhost:4200
```

#### Q: How do I run Stoobly in headless mode (proxy only)?

**A:** Use the `--headless` flag to disable the UI and run only the proxy.

**Example:**

```bash
stoobly-agent run --headless

# Only proxy runs on http://localhost:8080
```

#### Q: How do I run Stoobly without the proxy (UI only)?

**A:** Use the `--proxyless` flag to run only the web UI.

**Example:**

```bash
stoobly-agent run --proxyless

# Only UI runs on http://localhost:4200
```

#### Q: How do I run Stoobly on custom ports?

**A:** Use `--proxy-port` and `--ui-port` to specify custom ports.

**Example:**

```bash
# Custom ports
stoobly-agent run --proxy-port 9090 --ui-port 5000

# Proxy: http://localhost:9090
# UI: http://localhost:5000
```

#### Q: How do I run Stoobly on a specific host/interface?

**A:** Use `--proxy-host` and `--ui-host` to bind to specific network interfaces.

**Example:**

```bash
# Bind to all interfaces (default)
stoobly-agent run --proxy-host 0.0.0.0 --ui-host 0.0.0.0

# Bind to localhost only
stoobly-agent run --proxy-host 127.0.0.1 --ui-host 127.0.0.1

# Bind to specific IP
stoobly-agent run --proxy-host 192.168.1.100
```

#### Q: How do I run Stoobly in detached/background mode?

**A:** Use the `--detached` flag with a file path to redirect output and run in the background.

**Example:**

```bash
# Run in background
stoobly-agent run --detached /tmp/stoobly.log

# Returns PID
# 12345

# View logs
tail -f /tmp/stoobly.log

# Stop later
kill 12345
```

#### Q: How do I enable intercept mode on startup?

**A:** Use the `--intercept` flag to activate interception immediately.

**Example:**

```bash
# Enable intercept on startup
stoobly-agent run --intercept

# With specific mode
stoobly-agent run --intercept --intercept-mode mock
stoobly-agent run --intercept --intercept-mode record
```

#### Q: How do I set the intercept mode on startup?

**A:** Use the `--intercept-mode` option with one of: mock, record, replay, test.

**Example:**

```bash
# Start with mock mode
stoobly-agent run --intercept --intercept-mode mock

# Start with record mode
stoobly-agent run --intercept --intercept-mode record

# Start with test mode
stoobly-agent run --intercept --intercept-mode test
```

***

### Logging and Debugging

#### Q: How do I increase logging verbosity?

**A:** Use the `--log-level` option to control log output detail.

**Example:**

```bash
# Debug level (most verbose)
stoobly-agent run --log-level debug

# Info level (default)
stoobly-agent run --log-level info

# Warning level
stoobly-agent run --log-level warning

# Error level (least verbose)
stoobly-agent run --log-level error
```

#### Q: How do I control proxy flow detail output?

**A:** Use the `--flow-detail` option with levels 0-4.

**Example:**

```bash
# Level 0: No output
stoobly-agent run --flow-detail 0

# Level 1: Shortened URL + status code (default)
stoobly-agent run --flow-detail 1

# Level 2: Full URL + status + headers
stoobly-agent run --flow-detail 2

# Level 3: Level 2 + truncated response content
stoobly-agent run --flow-detail 3

# Level 4: Everything (no truncation)
stoobly-agent run --flow-detail 4
```

#### Q: How do I enable request logging?

**A:** Use the `--request-log-enable` flag to log all intercepted requests.

**Example:**

```bash
# Enable request logging
stoobly-agent run --request-log-enable

# With specific log level
stoobly-agent run --request-log-enable --request-log-level debug

# Without truncating log on startup
stoobly-agent run --request-log-enable --request-log-truncate=false
```

#### Q: How do I view the intercepted requests log?

**A:** Use the request logs list command while the agent is running or after. Use `-f` to stream logs in real time, or filter by method, URL, status code, and more.

**Examples:**

```bash
# Start with logging
stoobly-agent run --request-log-enable

# In another terminal, view logs
stoobly-agent request logs list

# Follow logs in real time (-f / --follow, Ctrl-C to stop)
stoobly-agent request logs list --follow

# Filter by log level
stoobly-agent request logs list --level error

# Filter by URL and method
stoobly-agent request logs list --url /api --method post
```

***

### SSL/TLS Configuration

#### Q: How do I specify a custom CA certificates directory?

**A:** Use the `--ca-certs-dir-path` option to set the CA certificate location.

**Example:**

```bash
stoobly-agent run --ca-certs-dir-path ~/.stoobly/ca_certs
```

#### Q: How do I use custom SSL certificates?

**A:** Use the `--certs` option to provide custom certificate files.

**Example:**

```bash
# Single domain certificate
stoobly-agent run --certs "example.com=/path/to/cert.pem"

# Wildcard certificate
stoobly-agent run --certs "*.example.com=/path/to/wildcard.pem"

# Multiple certificates
stoobly-agent run \
  --certs "api.example.com=/path/to/api-cert.pem" \
  --certs "app.example.com=/path/to/app-cert.pem"
```

#### Q: How do I provide a passphrase for encrypted certificates?

**A:** Use the `--cert-passphrase` option (note: visible in process list, prefer config file).

**Example:**

```bash
stoobly-agent run \
  --certs "example.com=/path/to/encrypted-cert.pem" \
  --cert-passphrase "my-secret-passphrase"
```

#### Q: How do I disable SSL certificate verification?

**A:** Use the `--ssl-insecure` flag to skip upstream SSL verification (use with caution).

**Example:**

```bash
# Disable SSL verification
stoobly-agent run --ssl-insecure

# Useful for self-signed certificates in development
```

***

### Proxy Modes

#### Q: What proxy modes are available?

**A:** Stoobly supports regular, transparent, socks5, reverse, and upstream proxy modes.

**Example:**

```bash
# Regular proxy (default)
stoobly-agent run --proxy-mode regular

# Transparent proxy
stoobly-agent run --proxy-mode transparent

# SOCKS5 proxy
stoobly-agent run --proxy-mode socks5

# Reverse proxy
stoobly-agent run --proxy-mode "reverse:https://api.example.com"

# Upstream proxy
stoobly-agent run --proxy-mode "upstream:http://corporate-proxy:3128"
```

#### Q: How do I set up a reverse proxy?

**A:** Use the reverse proxy mode with the target host specification.

**Example:**

```bash
# Reverse proxy to backend
stoobly-agent run --proxy-mode "reverse:https://api.backend.com"

# All requests to proxy will be forwarded to api.backend.com
curl http://localhost:8080/users
# Actually requests: https://api.backend.com/users
```

#### Q: How do I use an upstream proxy?

**A:** Use the upstream proxy mode to chain through another proxy.

**Example:**

```bash
# Chain through corporate proxy
stoobly-agent run --proxy-mode "upstream:http://proxy.corporate.com:8080"
```

***

### Lifecycle Hooks

#### Q: How do I use lifecycle hooks with the agent?

**A:** Use the `--lifecycle-hooks-path` option to specify a Python script with custom hooks.

**Example:**

```bash
# Create hooks script
cat > hooks.py << 'EOF'
def before_request(context):
    # Modify request before sending
    context.request.headers['X-Custom-Header'] = 'value'
    return context

def after_response(context):
    # Process response
    print(f"Response status: {context.response.status_code}")
    return context
EOF

# Run with hooks
stoobly-agent run --lifecycle-hooks-path ./hooks.py
```

***

### Mocking and Response Fixtures

#### Q: How do I use response fixtures for mocking?

**A:** Use the `--response-fixtures-path` option to provide YAML files with mock responses.

**Example:**

```bash
# Create fixtures file
cat > fixtures.yml << 'EOF'
- GET:
    /users/d+?:
      headers: {}
      path: <RELATIVE-PATH-TO-TO-RESPONSE-FILE>
      status_code: 200
- POST:
    /users:
      headers: {}
      path: <RELATIVE-PATH-TO-TO-RESPONSE-FILE>
      status_code: 200
EOF

# Run with fixtures
stoobly-agent run --response-fixtures-path ./fixtures.yml
```

#### Q: How do I serve static files for mocking?

**A:** Use the `--public-dir-path` option to serve files from a directory.

**Example:**

```bash
# Create public directory
mkdir public
echo '{"data": "test"}' > public/test.json

# Run with public directory
stoobly-agent run --public-dir-path ./public

# Access: http://localhost:8080/test.json
```

#### Q: How do I specify origin for fixtures and public directories?

**A:** Use the format `<PATH>:<ORIGIN>` to match specific origins.

**Example:**

```bash
stoobly-agent run \
  --response-fixtures-path "./fixtures.yml:https://api.example.com" \
  --public-dir-path "./public:https://cdn.example.com"
```

***

### Header Modification

#### Q: How do I modify request headers?

**A:** Use the `--modify-headers` option with header modification patterns.

**Example:**

```bash
# Add header to all requests
stoobly-agent run --modify-headers "/Authorization/Bearer token123"

# Remove header
stoobly-agent run --modify-headers "/X-Debug-Token/"

# Modify specific path
stoobly-agent run --modify-headers "/~u /api/.*//X-Custom/value"

# Multiple modifications
stoobly-agent run \
  --modify-headers "/Authorization/Bearer token" \
  --modify-headers "/X-API-Key/abc123"
```

***

### Quick Record Command

#### Q: How do I quickly record a single request without starting the agent?

**A:** Use the `record` command to make a request and store it.

**Example:**

```bash
# Record GET request
stoobly-agent record https://api.example.com/users

# Record POST request
stoobly-agent record -X POST -d '{"name":"John"}' https://api.example.com/users

# Record with custom headers
stoobly-agent record -H "Authorization: Bearer token" https://api.example.com/profile
```

#### Q: How do I record a request to a scenario?

**A:** Use the `--scenario-key` option to add the recorded request to a scenario.

**Example:**

```bash
# Record to scenario
stoobly-agent record https://api.example.com/users --scenario-key "<SCENARIO-KEY>"
```

#### Q: How do I save recorded response to a file?

**A:** Use the `-o` or `--output` option to write the response.

**Example:**

```bash
# Save response to file
stoobly-agent record https://api.example.com/users -o response.json

# View the file
cat response.json
```

#### Q: How do I format the recorded response output?

**A:** Use the `--format` option to control output format.

**Example:**

```bash
# Raw HTTP format
stoobly-agent record https://api.example.com/users --format raw
```

#### Q: How do I record requests with lifecycle hooks?

**A:** Use the `--lifecycle-hooks-path` option with the record command.

**Example:**

```bash
stoobly-agent record https://api.example.com/users --lifecycle-hooks-path ./hooks.py
```

***

### Quick Mock Command

#### Q: How do I quickly mock a request without starting the agent?

**A:** Use the `mock` command to replay a previously recorded request.

**Example:**

```bash
# Mock a URL (must have been recorded before)
stoobly-agent mock https://api.example.com/users
```

#### Q: How do I mock with custom headers?

**A:** Use the `-H` flag to add custom headers to the mock request.

**Example:**

```bash
stoobly-agent mock -H "Authorization: Bearer token" https://api.example.com/profile
```

#### Q: How do I mock a POST request?

**A:** Use `-X POST` and `-d` for the request body.

**Example:**

```bash
stoobly-agent mock -X POST -d '{"id":123}' https://api.example.com/users/search
```

#### Q: How do I mock with response fixtures?

**A:** Use the `--response-fixtures-path` option to provide mock data.

**Example:**

```bash
stoobly-agent mock https://api.example.com/users --response-fixtures-path ./fixtures.yml
```

#### Q: How do I mock with public directory files?

**A:** Use the `--public-dir-path` option to serve static files.

**Example:**

```bash
stoobly-agent mock https://cdn.example.com/data.json --public-dir-path ./public
```

#### Q: How do I save mocked response to a file?

**A:** Use the `-o` option to write the response to a file.

**Example:**

```bash
stoobly-agent mock https://api.example.com/users -o mock-response.json
```

***

### Connection Strategy

#### Q: What connection strategies are available?

**A:** Stoobly supports `eager` and `lazy` connection strategies for handling upstream connections.

**Example:**

```bash
# Eager: Connect immediately
stoobly-agent run --connection-strategy eager

# Lazy: Connect only when needed (default)
stoobly-agent run --connection-strategy lazy
```

***

### Complete Examples

#### Q: How do I set up a complete development environment?

**A:** Initialize, install CA cert, optionally create a scenario, then start agent with intercept mode.

**Example:**

```bash
# Step 1: Initialize
stoobly-agent init

# Step 2: Install CA certificate
stoobly-agent ca-cert install

# Step 3 (Optional): Create a scenario to organize requests
stoobly-agent scenario create "My User Flow"
# Output: Created scenario with key: <SCENARIO-KEY>

# Step 4: Start agent with intercept
stoobly-agent run --intercept --intercept-mode record

# Step 5: Configure your app to use proxy
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080

# Step 6: Make requests (they get recorded)
curl https://api.example.com/users
```

#### Q: How do I run Stoobly for API mocking in tests?

**A:** Start in headless mode with mock mode and fixtures.

**Example:**

```bash
# Start agent
stoobly-agent run \
  --headless \
  --intercept \
  --intercept-mode mock \
  --response-fixtures-path ./test-fixtures.yml \
  --public-dir-path ./test-data

# Run tests
npm test

# Tests use mocked responses
```

#### Q: How do I run Stoobly in CI/CD?

**A:** Use headless, detached mode with specific configuration.

**Example:**

```bash
#!/bin/bash
# CI/CD script

# Start agent in background
stoobly-agent run \
  --headless \
  --intercept \
  --intercept-mode test \
  --detached /tmp/stoobly.log \
  --log-level info

# Get PID
AGENT_PID=$(cat /tmp/stoobly.log | head -1)

# Wait for agent to start
sleep 2

# Run tests
npm test

# Stop agent
kill $AGENT_PID
```

***

### Environment Variables

#### Q: How do I enable latency simulation for mocked responses?

**A:** Set the `AGENT_SIMULATE_LATENCY` environment variable to enable latency simulation. When enabled, Stoobly will simulate the expected response latency based on the `X-Stoobly-Response-Latency` header value in milliseconds.

**Example:**

```bash
# Enable latency simulation
export AGENT_SIMULATE_LATENCY=1

# Start the agent
stoobly-agent run --intercept --intercept-mode mock

# Mocked responses will now simulate latency based on the X-Stoobly-Response-Latency header
```

**How it works:**

* The latency simulation calculates wait time as: `expected_latency - estimated_rtt_network_latency - api_latency`
* `expected_latency` comes from the `X-Stoobly-Response-Latency` response header (in milliseconds)
* `estimated_rtt_network_latency` is fixed at 15ms
* `api_latency` is the time elapsed since the request started
* If the calculated wait time is positive, Stoobly will sleep for that duration before returning the response

**Use cases:**

* Testing how your application handles slow API responses
* Simulating real-world network conditions during development
* Validating timeout and retry logic

**Note:** This feature only works in mock mode and requires the `X-Stoobly-Response-Latency` header to be present in the mocked response.

***

### Troubleshooting

#### Q: How do I debug connection issues?

**A:** Increase log level and flow detail for verbose output.

**Example:**

```bash
stoobly-agent run --log-level debug --flow-detail 4
```

#### Q: How do I verify the agent is running?

**A:** Check the proxy and UI ports.

**Example:**

```bash
# Check proxy
curl -x http://localhost:8080 http://example.com

# Check UI
curl http://localhost:4200
```

#### Q: What do I do if ports are already in use?

**A:** Use custom ports to avoid conflicts.

**Example:**

```bash
# Use different ports
stoobly-agent run --proxy-port 9090 --ui-port 5000
```

***

### Quick Reference

#### Q: What are the essential commands?

**A:** Here's a quick reference of the most common commands:

**Example:**

```bash
# Check version
stoobly-agent --version

# Initialize
stoobly-agent init

# Run agent (full)
stoobly-agent run

# Run headless
stoobly-agent run --headless

# Run with intercept
stoobly-agent run --intercept --intercept-mode record

# Run detached
stoobly-agent run --detached /tmp/stoobly.log

# Quick record
stoobly-agent record https://api.example.com/users

# Quick mock
stoobly-agent mock https://api.example.com/users

# Custom ports
stoobly-agent run --proxy-port 9090 --ui-port 5000

# Debug mode
stoobly-agent run --log-level debug --flow-detail 4

# With fixtures
stoobly-agent run --response-fixtures-path ./fixtures.yml

# With lifecycle hooks
stoobly-agent run --lifecycle-hooks-path ./hooks.py
```


# Scaffold

## Stoobly Scaffold Commands - Questions & Answers for Team Use

Scaffold commands enable Stoobly for team collaboration. The workflow is: create an app, add services, and use the automatically generated record, mock, test, and develop workflows for each service. Custom workflows can be created as needed. **Recommended:** describe your app and services in a declarative `.stoobly/scaffold.yml` and apply it with `stoobly-agent scaffold apply` — the individual `scaffold app create` / `scaffold service create` commands are still available and useful for one-off changes.

***

### Getting Started with Scaffold

#### Q: What's the recommended way to set up a scaffold?

**A:** Create a declarative config at `.stoobly/scaffold.yml` with your app and service creation steps, then apply it with `stoobly-agent scaffold apply`. This keeps the whole setup reviewable, version-controlled, and reproducible by teammates with one command. For the full command reference and config schema, see:

{% content-ref url="/pages/vNbSv8Y3FUGMz3PL3GyX" %}
[Apply](/faq/scaffold/apply)
{% endcontent-ref %}

**Example:**

```yaml
# .stoobly/scaffold.yml
version: 1
commands:
  # Creates .stoobly/services/ in the current directory
  # For E2E testing, add plugin: [playwright] or plugin: [cypress]
  - resource: app
    action: create
    options:
      app_name: my-app
      plugin: [playwright]

  # API service runs on localhost:8080, exposed as api.local:80
  # Note: port and upstream_port must differ when using local: true
  # Run your API service on port 8080 (not 80)
  - resource: service
    action: create
    options:
      service_name: api
      hostname: api.local
      port: 80
      scheme: http
      local: true
      upstream_port: 8080

  # Example: Start record workflow
  # - resource: workflow
  #   action: up
  #   options:
  #     workflow_name: record
  #     ca_certs_install_confirm: y
  #
  # stoobly-agent intercept enable

  # Example: Start mock workflow
  # - resource: workflow
  #   action: up
  #   options:
  #     workflow_name: mock
  #
  # stoobly-agent intercept enable

  # Example: Start test workflow
  # - resource: workflow
  #   action: up
  #   options:
  #     workflow_name: test
  #
  # stoobly-agent intercept enable
```

```bash
# Validate, then apply
stoobly-agent scaffold apply .stoobly/scaffold.yml --dry-run
stoobly-agent scaffold apply .stoobly/scaffold.yml
```

#### Q: What is scaffolding in Stoobly?

**A:** Scaffolding creates a structured project setup for team collaboration, with workflows for recording, mocking, and testing HTTP requests across multiple services. The scaffold structure is created under `.stoobly/services/` in the current directory.

**Example:**

```yaml
# .stoobly/scaffold.yml
version: 1
commands:
  - resource: app
    action: create
    options:
      app_name: my-app

  - resource: service
    action: create
    options:
      service_name: api
```

```bash
stoobly-agent scaffold apply .stoobly/scaffold.yml
```

Or with the individual commands directly:

```bash
# Create a scaffold app (creates .stoobly/services/ in current directory)
stoobly-agent scaffold app create my-app

# Add a service
stoobly-agent scaffold service create api
```

#### Q: Why should I use scaffold for team development?

**A:** Scaffold provides version-controlled configuration, consistent environments across team members, and automated workflow management for recording, mocking, and testing APIs.

**Example:**

```bash
# Team member 1 creates the scaffold from .stoobly/scaffold.yml
stoobly-agent scaffold apply .stoobly/scaffold.yml

# Team member 2 clones and reproduces the exact same setup
git clone <repo>
stoobly-agent scaffold apply .stoobly/scaffold.yml
stoobly-agent scaffold workflow up test 
```

***

### Creating an Application

#### Q: How do I create a new scaffold application?

**A:** Use `scaffold app create` with your application name to generate the scaffold structure under `.stoobly/services/` in the current directory. **By default, the app is created with local runtime** (workflows run directly on your machine). To use Docker runtime instead, specify `--runtime docker`.

**Example:**

```bash
# Creates app with local runtime (default)
stoobly-agent scaffold app create my-app
# Creates .stoobly/services/ structure in current directory

# Or explicitly specify local runtime
stoobly-agent scaffold app create my-app --runtime local

# Or use Docker runtime
stoobly-agent scaffold app create my-app --runtime docker
```

#### Q: How do I create a scaffold app in a specific directory?

**A:** By default, the scaffold is created in the current directory. Use the `--app-dir-path` option only when you need to specify a different location.

**Example:**

```bash
# Create in current directory (default)
stoobly-agent scaffold app create my-app

# Create in specific directory (optional)
stoobly-agent scaffold app create my-app --app-dir-path /path/to/projects
```

#### Q: How do I create a scaffold app with custom ports?

**A:** Use `--proxy-port` and `--ui-port` options to specify custom ports for the proxy and UI.

**Example:**

```bash
stoobly-agent scaffold app create my-app --proxy-port 9090 --ui-port 5000
```

#### Q: How do I choose the proxy mode for my scaffold app?

**A:** Use the `--proxy-mode` option to select how Stoobly proxies requests for your app. The default is `forward`, which exposes a single proxy endpoint that your clients/tests connect to (typical forward-proxy setup). The `reverse` mode is only supported with Docker runtime and is recommended when you want to route traffic via hostnames (e.g. `api.local`) and manage `/etc/hosts` entries.

**Example:**

```bash
# Default forward proxy mode (no option needed)
stoobly-agent scaffold app create my-app

# Explicitly set forward proxy mode
stoobly-agent scaffold app create my-app --proxy-mode forward

# Reverse proxy mode (Docker runtime only)
stoobly-agent scaffold app create my-app \
  --runtime docker \
  --proxy-mode reverse
```

**Important:**

* Using `--proxy-mode reverse` with local runtime is not allowed and will fail with an error.
* When using reverse proxy mode with Docker, Stoobly can manage `/etc/hosts` entries for your service hostnames via `scaffold hostname install` or the hostname prompts during `scaffold workflow up`.

#### Q: What does the copy-on-workflow-up (`--copy-on-workflow-up`) option do?

**A:** The `--copy-on-workflow-up` option enables isolated workflow run behavior. When enabled, Stoobly copies the scaffold files from your app directory (`--app-dir-path`) into the Stoobly context directory on each `scaffold workflow up` run. This is useful when you want workflow runs to operate on an isolated copy of the scaffold (for example in CI or when using workflow namespaces), while keeping your source scaffold under version control in your app directory.

**Example:**

```bash
# Enable copy-on-workflow-up behavior
stoobly-agent scaffold app create my-app --copy-on-workflow-up

# Later, when you start a workflow:
stoobly-agent scaffold workflow up record
# Stoobly copies the scaffold into its context tmp directory before running
```

**Notes:**

* `--proxy-mode-reverse` affects how scaffold files are managed at runtime; it does not change the CLI commands you use.
* This option can reduce coupling between your app directory and the runtime context, especially when multiple workflows or namespaces run concurrently.

#### Q: How do I create a scaffold app with test framework integrations?

**A:** Use the `--plugin` option to include Cypress or Playwright integrations.

**Example:**

```bash
# With Cypress
stoobly-agent scaffold app create my-app --plugin cypress

# With Playwright
stoobly-agent scaffold app create my-app --plugin playwright

# With both
stoobly-agent scaffold app create my-app --plugin cypress --plugin playwright
```

#### Q: What runtime environments are supported for scaffold apps?

**A:** Scaffold supports two runtime environments: **local (default)** and Docker. When you run `scaffold app create` without specifying `--runtime`, it defaults to local runtime, which runs workflows directly on your machine. Use `--runtime docker` to run workflows in Docker containers instead.

**Example:**

```bash
# Local runtime (default - no --runtime option needed)
stoobly-agent scaffold app create my-app

# Or explicitly specify local runtime
stoobly-agent scaffold app create my-app --runtime local

# Docker runtime (must be explicitly specified)
stoobly-agent scaffold app create my-app --runtime docker
```

#### Q: How do I check whether my app is configured with local or Docker runtime?

**A:** Check the `.stoobly/services/.config.yml` file and look for the `APP_RUNTIME` configuration property to see which runtime is configured.

**Example:**

```bash
# View the configuration file
cat .stoobly/services/.config.yml

# Or check for the specific property
grep APP_RUNTIME .stoobly/services/.config.yml
```

The `APP_RUNTIME` property will indicate whether the app is configured to run with `local` or `Docker`.

#### Q: What files are created when I scaffold an app?

**A:** Scaffolding creates a `.stoobly/services/` directory in the current directory with service definitions and workflow templates.

**Example:**

```bash
stoobly-agent scaffold app create my-app
ls -la .stoobly/services/
# build .config.yml entrypoint .gitignore
```

***

### Creating Services

#### Q: How do I add a service to my scaffold app?

**A:** Use `scaffold service create` with the service name to add a new service. By default, commands use the current directory. Use `--app-dir-path` only when you need to specify a different location.

**Example:**

```bash
# From within the app directory (default)
stoobly-agent scaffold service create api

# Or specify the app directory
stoobly-agent scaffold service create api --app-dir-path ./my-app
```

**Note:** If you maintain `.stoobly/scaffold.yml` to recreate your setup from scratch, add a matching `service` step to it too, so `stoobly-agent scaffold apply .stoobly/scaffold.yml` stays reproducible. See [Apply](/faq/scaffold/apply) for the config schema.

#### Q: How do I create a service with a custom hostname?

**A:** Use the `--hostname` option to specify a custom hostname for the service.

**Example:**

```bash
# From within the app directory
stoobly-agent scaffold service create api --hostname api.example.com
```

#### Q: How do I create a service that proxies to a service that does not run on localhost?

**A:** Configure the service using `--hostname`, `--port`, and `--scheme` to define how clients connect to Stoobly. Only use `--upstream-hostname`, `--upstream-port`, and `--upstream-scheme` when the upstream server differs from these values.

**Important:**

* The `--upstream-*` options are overrides, not replacements. Always set `--hostname`, `--port`, and `--scheme` first, then add `--upstream-*` options **only when they differ**. If the upstream uses the same port and scheme, do not specify `--upstream-port` or `--upstream-scheme`.

**Example:**

```bash
# Example 1. When upstream differs from service (e.g., proxying production API locally)
# Clients connect to http://api.local:80 → Stoobly forwards to https://api.production.com:443
stoobly-agent scaffold service create api \
  --hostname api.local \
  --port 80 \
  --scheme http \
  --upstream-hostname api.production.com \
  --upstream-port 443 \
  --upstream-scheme https

# Example 2. When upstream matches service hostname and port (no --upstream-* needed)
# Clients connect to http://app.example.com:80 → Stoobly forwards to http://app.example.com:80
stoobly-agent scaffold service create ui \
  --hostname app.example.com \
  --port 80 \
  --scheme http
```

#### Q: How do I create a service for the application under test?

**A:** Create a service for your main application (the application being tested) using only the `test` workflow. Do not use `--local`, `--workflow record`, or `--workflow mock` options since the application under test should not be recorded or mocked.

**Example:**

```
# Application under test service is run locally for development but built when testing,  running on http://localhost:4200
# DO NOT set --local option, this is the service used for development or testing
# DO NOT set --workflow record and --workflow mock options, main application should not have either
# Specify a hostname, e.g. main.local
# Specify a port e.g. 4200
# Run your frontend service on the same port
stoobly-agent scaffold service create main.local \
  --hostname main.local \
  --port 4200 \
  --scheme http \
  --workflow test
```

#### Q: For Docker runtime, how do I create a service that proxies to a service that runs on localhost?

**A:** Use `--hostname`, `--port`, and `--scheme` to define how clients connect to Stoobly, then add the `--local` flag. You must specify `--upstream-port` with a different port than `--port`, and run your local service on that upstream port.

**Important:**

* Docker runtime uses a **forward proxy** or **reverse proxy**
* `--port` - The port Stoobly listens on (what clients/tests connect to)
* `--scheme` - The scheme Stoobly uses (http or https)
* `--local` - Automatically sets `--upstream-hostname` to localhost
* `--upstream-port` - **Required and must be different from `--port`** - This is where your local service runs
* `--upstream-scheme` - **Optional** - Only specify if your local service uses a different scheme than `--scheme`
* Do not specify `--upstream-hostname` when using `--local` (it will be ignored)
* **You must run your local service on `--upstream-port`, not on `--port`**
* Different types of services have different recommended option configurations, match against the following examples.

**Example:**

```bash
# Local API service running on http://localhost:3000
# Specify a hostname, e.g. api.local
# Specify a port e.g. 3000
# Run your API service on a different port from 3000, e.g. 3001
# Clients connect to http://api.local:3000 → Stoobly forwards to http://localhost:3001
stoobly-agent scaffold service create api.local \
  --hostname api.local \
  --port 3000 \
  --scheme http \
  --local \
  --upstream-port 3001
```

#### Q: For local runtime, how do I create a service that proxies to a service that runs on localhost?

**A:** Set the hostname to `localhost` and do not use the `--local` option. Specify `--port` to match the port where your local service runs.

**Important:**

* Local runtime uses a **forward proxy**
* `--hostname` - Must be `localhost` for local runtime
* `--port` - The port where your local service runs (and where Stoobly will proxy)
* `--scheme` - The scheme your service uses (http or https)
* `--local` - **Do not use** this option with local runtime (it's only for Docker runtime)

**Example:**

```bash
# Local API service running on http://localhost:3000
# Hostname must be localhost for local runtime
# Port matches the port your service runs on
# Do NOT use --local option
stoobly-agent scaffold service create api \
  --hostname localhost \
  --port 3000 \
  --scheme http
```

#### Q: How do I set the port for a service?

**A:** Use the `--port` option to specify the port where Stoobly exposes the service (the port your tests/clients will use). For local services (using `--local`), you must specify `--upstream-port` with a different port and run your service on that upstream port.

**Key difference:**

* `--port` - The port Stoobly listens on (what you connect to in tests) - **always required**
* `--upstream-port` - The port of the actual service Stoobly proxies to - **required when using `--local` and must be different from `--port`**

**Example:**

```bash
# Remote service where Stoobly port matches upstream port (no --upstream-port needed)
# Specify a hostname, e.g. api.local
# Specify a port, e.g. 8080
# Clients connect to http://api.local:8080 → Stoobly forwards to http://api.local:8080
stoobly-agent scaffold service create api \
  --hostname api.local \
  --port 8080 \
  --scheme http

# Docker runtime local service (not applicable to local runtime) - ports must differ
# Local API service normally runs on http://localhost:3000
# Specify a hostname, e.g. api.local
# Specify a port e.g. 3000
# Run your API service on a different port from the specified one from 3000, e.g. 3001
# Clients connect to http://api.local:3000 → Stoobly forwards to http://localhost:3001
stoobly-agent scaffold service create api \
  --hostname api.local \
  --port 3000 \
  --scheme http \
  --local \
  --upstream-port 3001
```

#### Q: How do I control the startup order of services?

**A:** Use the `--priority` option (1.0-9.0) where lower values start first.

**Example:**

```bash
# Database starts first (priority 1)
stoobly-agent scaffold service create database --priority 1.0

# API starts second (priority 2)
stoobly-agent scaffold service create api --priority 2.0

# Frontend starts last (priority 3)
stoobly-agent scaffold service create frontend --priority 3.0
```

#### Q: How do I create a service with environment variables?

**A:** Use the `--env` option (can be used multiple times) to set environment variables.

**Example:**

```bash
stoobly-agent scaffold service create api \
  --env DATABASE_URL=postgres://localhost/db \
  --env API_KEY=secret123
```

#### Q: How do I create a service with specific workflows?

**A:** By default, all four workflows (record, mock, test, develop) are created. Use the `--workflow` option only when you want to create a subset of workflows.

**Common pattern:** Frontend services that serve static assets typically only need the `test` workflow, as they don't require recording or mocking. The test workflow serves the built application from fixtures for E2E testing.

**Example:**

```bash
# All workflows (default - no --workflow needed)
stoobly-agent scaffold service create api

# Frontend service - only test workflow (serves static assets from fixtures)
stoobly-agent scaffold service create frontend \
  --hostname app.local \
  --workflow test

# Only mock and test workflows
stoobly-agent scaffold service create api --workflow mock --workflow test

# Only record workflow
stoobly-agent scaffold service create api --workflow record

# Only develop workflow
stoobly-agent scaffold service create api --workflow develop
```

#### Q: What are the default workflows created for each service?

**A:** By default, four workflows are created: `record` (capture requests), `mock` (serve mocked responses), `test` (validate responses), and `develop` (redirect requests to a local development server via synced rewrite rules). Use `--workflow` if you want to create only a subset.

**Example:**

```bash
stoobly-agent scaffold service create api
# Creates: record, mock, test, and develop workflows automatically

stoobly-agent scaffold service create api --workflow mock --workflow test
# Creates only mock and test, skipping record and develop
```

#### Q: How do I set up a frontend service to serve static assets for E2E testing?

**A:** Frontend services typically only need the `test` workflow since they serve static assets from fixtures rather than recording or mocking requests. Modify the service's `test/init` script (located at `.stoobly/services/<service-name>/test/init`) to copy your built application to the public fixture folder.

**Example:**

```bash
# Create frontend service with only test workflow
stoobly-agent scaffold service create frontend \
  --hostname app.local \
  --workflow test

# Edit .stoobly/services/frontend/test/init to copy built assets
# Add this to the init script:
# cp -r $APP_DIR_PATH/dist/. .stoobly/fixtures/public/
```

**Example init script:**

```bash
#!/bin/bash
# .stoobly/services/frontend/test/init

# Copy built frontend assets to public fixtures folder
cp -r $APP_DIR_PATH/dist/dist/. .stoobly/fixtures/public/

# The frontend service will serve these static files during E2E tests
```

This setup allows your E2E tests to request the application under test from the frontend service, which serves the static assets from the fixtures folder.

***

### Managing Services

#### Q: How do I list all services in my scaffold app?

**A:** Use `scaffold service list` to display all configured services. Run from your app directory, or use `--app-dir-path` to specify the location.

**Example:**

```bash
# From within the app directory (default)
stoobly-agent scaffold service list

# Or specify the app directory
stoobly-agent scaffold service list --app-dir-path ./my-app
```

#### Q: How do I view details about a specific service?

**A:** Use `scaffold service show` with the service name.

**Example:**

```bash
stoobly-agent scaffold service show api
```

#### Q: How do I list services in a specific format?

**A:** Use the `--format` option to specify output format (table, json, csv).

**Example:**

```bash
# JSON format
stoobly-agent scaffold service list --format json

# CSV format
stoobly-agent scaffold service list --format csv
```

#### Q: How do I filter services by workflow?

**A:** Use the `--workflow` option to filter services by their workflows.

**Example:**

```bash
# Show only services with record workflow
stoobly-agent scaffold service list --workflow record

# Show services with mock or test workflows
stoobly-agent scaffold service list --workflow mock --workflow test
```

#### Q: How do I update a service configuration?

**A:** Use `scaffold service update` with the options you want to change.

**Example:**

```bash
stoobly-agent scaffold service update api \
  --hostname api.newdomain.com \
  --port 9090
```

**Note:** If you maintain `.stoobly/scaffold.yml`, update the matching `service` step's options too, so `stoobly-agent scaffold apply .stoobly/scaffold.yml` stays reproducible. See [Apply](/faq/scaffold/apply) for the config schema.

#### Q: How do I rename a service?

**A:** Use `scaffold service update` with the `--name` option.

**Example:**

```bash
stoobly-agent scaffold service update old-api --name new-api
```

**Note:** If you maintain `.stoobly/scaffold.yml`, update the matching `service` step to use the new `service_name`, so `stoobly-agent scaffold apply .stoobly/scaffold.yml` stays reproducible. See [Apply](/faq/scaffold/apply) for the config schema.

#### Q: How do I delete a service?

**A:** Use `scaffold service delete` with the service name.

**Example:**

```bash
stoobly-agent scaffold service delete api
```

**Note:** If you maintain `.stoobly/scaffold.yml`, remove the matching `service` step from it too, so `stoobly-agent scaffold apply .stoobly/scaffold.yml` stays reproducible. See [Apply](/faq/scaffold/apply) for the config schema.

***

### Working with Workflows

#### Q: What workflows are available by default?

**A:** Four workflows are created by default for each service: `record` (capture requests), `mock` (serve mocked responses), `test` (validate responses), and `develop` (redirect requests to a local development server). See "What is the develop workflow and how do I use it?" below for details on develop.

**Example:**

```bash
# Start record workflow
stoobly-agent scaffold workflow up record
stoobly-agent intercept enable

# Start mock workflow
stoobly-agent scaffold workflow up mock
stoobly-agent intercept enable

# Start test workflow
stoobly-agent scaffold workflow up test
stoobly-agent intercept enable

# Start develop workflow
stoobly-agent scaffold workflow up develop
stoobly-agent intercept enable
```

#### Q: How do I start a workflow?

**A:** Use `scaffold workflow up` with the workflow name to start all services in that workflow. Run from your app directory, or use `--app-dir-path` to specify the location.

**Example:**

```bash
# From within the app directory (default)
stoobly-agent scaffold workflow up test

# Or specify the app directory
stoobly-agent scaffold workflow up test
```

#### Q: How do I stop a workflow?

**A:** Use `scaffold workflow down` with the workflow name to stop all services.

**⚠️ IMPORTANT:** Always use `stoobly-agent scaffold workflow down` to stop workflows. **DO NOT** use Unix commands like `pkill`, `kill`, or `docker stop` - these can leave the system in an inconsistent state.

**Example:**

```bash
stoobly-agent scaffold workflow down record
```

#### Q: How do I check if a workflow is running?

**A:** Use `scaffold workflow show` to determine if a scaffold workflow is currently running. If a workflow is running, it shows the namespace, runtime (Docker or local), and when it was started.

**Example:**

```bash
stoobly-agent scaffold workflow show
```

```
═════════════════════════════════════════════
  Workflow: mock
═════════════════════════════════════════════
  Namespace   mock
  Status      running
  Runtime     docker
  Started     2025-11-14 10:32:17
```

To also see the scaffold services running under the workflow, use the `--verbose` flag:

```bash
stoobly-agent scaffold workflow show --verbose
```

#### Q: How do I view logs from a workflow?

**A:** There are two log commands and both are important. Use `scaffold request logs list` to see what requests were intercepted and whether they were mocked or passed through — this is the first thing to check when verifying mock behavior or debugging. Use `scaffold workflow logs` for the raw workflow process output such as startup errors and configuration issues.

**Example:**

```bash
# Show intercepted request logs — confirms mock success/failure per request
stoobly-agent scaffold request logs list mock

# Stream request logs in real time
stoobly-agent scaffold request logs list mock --follow

# Show raw workflow process output (startup errors, config issues)
stoobly-agent scaffold workflow logs mock
```

Replace `mock` with `record` or `test` depending on which workflow is running.

#### Q: What is the develop workflow and how do I use it?

**A:** The `develop` workflow redirects requests for a service's real hostname to a local development server, instead of recording, mocking, or testing fixed responses. It's useful when you want to work against a service your app already calls (e.g. a staging or production URL) while transparently routing that traffic to code you're actively developing locally.

The redirection is driven by [rewrite rules](https://docs.stoobly.com/core-concepts/agent/proxy-settings/rewrite-rules) generated from the service's configured upstream hostname, port, and scheme. It's created automatically along with record, mock, and test — no extra flag needed unless you're limiting a service to a subset of workflows (see "How do I create a service with specific workflows?" above).

**Example:**

```bash
# Creates record, mock, test, AND develop workflows for the service
stoobly-agent scaffold service create api

# Sync develop rewrite rules from the service's upstream hostname, port, and scheme
# Re-run this any time the service's upstream configuration changes
stoobly-agent scaffold workflow rewrite develop

# Start the develop workflow
stoobly-agent scaffold workflow up develop
stoobly-agent intercept enable
```

#### Q: How do I start a workflow with specific services only?

**A:** Use the `--service` option to select which services to run.

**Example:**

```bash
# Run only api and database services
stoobly-agent scaffold workflow up test --service api --service database
```

#### Q: How do I start a workflow in detached mode?

**A:** Use the `--detached` flag to run the workflow in the background.

**Example:**

```bash
stoobly-agent scaffold workflow up test --detached
```

#### Q: How do I skip hostname installation prompts?

**A:** Use the `--hostname-install-confirm` option to automatically confirm or deny hostname installation.

**Example:**

```bash
# Automatically confirm
stoobly-agent scaffold workflow up record --hostname-install-confirm y

# Automatically deny
stoobly-agent scaffold workflow up record --hostname-install-confirm n
```

#### Q: How do I skip CA certificate installation prompts?

**A:** Use the `--ca-certs-install-confirm` option to automatically confirm or deny CA certificate installation.

**Example:**

```bash
stoobly-agent scaffold workflow up record --ca-certs-install-confirm y
```

#### Q: Which workflows support custom namespaces?

**A:** Namespaces are **only supported by test workflows** and custom workflows based on the test workflow template. Record and mock workflows do **not** support namespaces.

**Supported:**

* `test` workflow
* Custom workflows created with `--template test`

**Not Supported:**

* `record` workflow
* `mock` workflow
* Custom workflows created with `--template record` or `--template mock`

**Example:**

```bash
# Supported - test workflow with namespace
stoobly-agent scaffold workflow up test --namespace my-namespace

# Supported - custom workflow based on test workflow template
stoobly-agent scaffold workflow create my-test --template test --service api
stoobly-agent scaffold workflow up my-test --namespace my-namespace

# NOT Supported - record workflow (will cause errors)
stoobly-agent scaffold workflow up record --namespace my-namespace  # Does NOT work

# NOT Supported - mock workflow (will cause errors)
stoobly-agent scaffold workflow up mock --namespace my-namespace  # Does NOT work
```

***

### Creating Custom Workflows

#### Q: How do I create a custom workflow?

**A:** Use `scaffold workflow create` with a workflow name and template to create a custom workflow.

**Example:**

```bash
# Create a custom workflow based on the record template
stoobly-agent scaffold workflow create staging \
  --template record \
  --service api
```

#### Q: What templates can I use for custom workflows?

**A:** You can use `mock`, `record`, or `test` as templates for custom workflows.

**Example:**

```bash
# Custom workflow based on mock template
stoobly-agent scaffold workflow create dev-mock --template mock --service api

# Custom workflow based on test workflow template
stoobly-agent scaffold workflow create integration-test --template test --service api
```

#### Q: How do I create a custom workflow for multiple services?

**A:** Use multiple `--service` options to include multiple services in the workflow.

**Example:**

```bash
stoobly-agent scaffold workflow create full-stack \
  --template record \
  --service api \
  --service frontend \
  --service database
```

#### Q: How do I copy an existing workflow?

**A:** Use `scaffold workflow copy` to duplicate a workflow with a new name.

**Example:**

```bash
# Copy record workflow to staging workflow
stoobly-agent scaffold workflow copy record staging \
  --service api
```

***

### SSL/TLS Certificate Management

#### Q: How do I generate SSL certificates for HTTPS services?

**A:** Use `scaffold app mkcert`.

**Example:**

```bash
# Generate SSL certs for all services
stoobly-agent scaffold app mkcert

# Generate SSL certs for all services in a workflow
stoobly-agent scaffold app mkcert --workflow <WORKFLOW-NAME>
```

#### Q: How do I generate certificates for specific services only?

**A:** Use the `--service` option with the mkcert command.

**Example:**

```bash
stoobly-agent scaffold app mkcert --service api --service frontend
```

***

### Hostname Management

#### Q: How do I install hostnames for services?

**A:** Use `scaffold hostname install` to add service hostnames to `/etc/hosts`.

**Example:**

```bash
stoobly-agent scaffold hostname install --workflow record
```

#### Q: How do I uninstall hostnames for services?

**A:** Use `scaffold hostname uninstall` to remove service hostnames from `/etc/hosts`.

**Example:**

```bash
stoobly-agent scaffold hostname uninstall --workflow record
```

#### Q: How do I manage hostnames for specific services?

**A:** Use the `--service` option to target specific services.

**Example:**

```bash
stoobly-agent scaffold hostname install --workflow record --service api
```

***

### Team Collaboration Workflows

#### Q: How do I set up a scaffold project for my team?

**A:** Create the scaffold app, add services, and commit the configuration to version control so team members can use it.

**Example:**

```bash
stoobly-agent scaffold app create team-project

stoobly-agent scaffold service create local-api \
  --hostname api.local \
  --local \
  --port 3000 \
  --scheme http \
  --upstream-port 3001

stoobly-agent scaffold service create staging-api \
  --hostname api.staging \
  --port 443 \
  --scheme https

stoobly-agent scaffold service create frontend \
  --hostname frontend.local \
  --port 4200 \
  --scheme http \
  --workflow test

# Commit to git
git add .stoobly/
git commit -m "Add Stoobly scaffold configuration"
git push

# Team members use it
git pull
stoobly-agent scaffold workflow up mock
stoobly-agent intercept enable
```

#### Q: How do I share recorded requests with my team?

**A:** Use scenario snapshots to create committable files that can be shared via version control.

**Example:**

```bash
# Record requests
stoobly-agent scaffold workflow up record
stoobly-agent intercept enable

# Create snapshot
stoobly-agent scenario snapshot <SCENARIO-KEY>

# Commit and push
git add .stoobly/snapshots/
git commit -m "Add API request snapshots"
git push
```

#### Q: How do I run the same workflow across different environments?

**A:** Create custom workflows for each environment using templates.

**Example:**

```bash
# Create staging workflow
stoobly-agent scaffold workflow create staging --template record --service api

# Create production workflow
stoobly-agent scaffold workflow create production --template record --service api

# Use them
stoobly-agent scaffold workflow up staging
stoobly-agent scaffold workflow up production
```

***

### Quick Reference

#### Q: What's the complete end-to-end workflow for setting up and using a team project?

**A:** This is a comprehensive step-by-step guide covering the full workflow from initial setup through running tests and sharing results with your team.

**Example:**

```bash
# 1. Create app
stoobly-agent scaffold app create team-project

# 2. Add services
stoobly-agent scaffold service create local-api \
  --hostname api.local \
  --local \
  --port 3000 \
  --scheme http \
  --upstream-port 3001

stoobly-agent scaffold service create staging-api \
  --hostname api.staging \
  --port 443 \
  --scheme https

stoobly-agent scaffold service create frontend \
  --hostname frontend.local \
  --port 4200 \
  --scheme http \
  --workflow test

# 3. Start record workflow
stoobly-agent scaffold workflow up record
stoobly-agent intercept enable

# 4. Make requests (they get recorded)
curl http://api.local/users

# 5. Stop workflow
stoobly-agent scaffold workflow down record

# 6. Start mock workflow
stoobly-agent scaffold workflow up mock
stoobly-agent intercept enable

# 7. Run tests against mocks
npm test

# 8. Create snapshots and commit
stoobly-agent scenario snapshot <SCENARIO-KEY> 
git add .stoobly/
git commit -m "Add scaffold and snapshots"
git push

# 9. Setup test workflow
# Update .stoobly/services/entrypoint/test/run to run test command e.g. `npm test`

# 10. Start test workflow
stoobly-agent scaffold workflow up test
stoobly-agent intercept enable
```


# Apply

## Stoobly Scaffold Apply - Questions & Answers

{% hint style="info" %}
`stoobly-agent scaffold apply` requires **stoobly-agent v2.5.0 or later**.
{% endhint %}

`scaffold apply` runs an ordered list of scaffold CLI commands from a config file (by convention, `.stoobly/scaffold.yml`). Each step in the config maps 1:1 to `stoobly-agent scaffold <resource> <action> …`, so an entire app-and-services setup can be written once, reviewed in a pull request, checked into version control, and reproduced by anyone on the team with a single command — instead of typing out a sequence of `scaffold app create` / `scaffold service create` invocations by hand.

***

### Getting Started

#### Q: How do I apply a scaffold config?

**A:** Point `scaffold apply` at the config file. Validate first with `--dry-run`, then apply for real.

**Example:**

```bash
stoobly-agent scaffold apply .stoobly/scaffold.yml --dry-run
stoobly-agent scaffold apply .stoobly/scaffold.yml
```

#### Q: What does the CLI command look like?

**A:**

```
Usage: stoobly-agent scaffold apply [OPTIONS] PATH

  Apply scaffold commands from a config file

Options:
  --dry-run             If set, runs validation and logs only.
  --format [yaml|json]  Config file format.  [default: yaml]
  -h, --help            Show this message and exit.
```

| Argument / option | Description                                                                                                                                                                        |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PATH`            | Path to the config file. **Required** — there is no implicit lookup of `.stoobly/scaffold.yml`; you must always pass the path. Must be an existing regular file (not a directory). |
| `--dry-run`       | Validates the config and logs what each step would do, without invoking any commands.                                                                                              |
| `--format`        | `yaml` (default) or `json`. Does not sniff the file extension — a `.json` file applied without `--format json` is parsed as YAML.                                                  |

***

### The Config File

#### Q: What's the top-level structure of `scaffold.yml`?

**A:** Two required keys: `version` (must be the integer `1`) and `commands` (a non-empty ordered list of steps).

**Example:**

```yaml
version: 1
commands:
  - resource: app
    action: create
    options:
      app_name: my-app

  - resource: service
    action: create
    options:
      service_name: api
      hostname: api.example.com
      scheme: https
      port: 443
```

Steps run **in order** and stop on the first failure.

#### Q: What does a step look like?

**A:** Each entry in `commands` has a `resource`, an `action`, and an optional `options` mapping.

| Key        | Required | Description                                                                     |
| ---------- | -------- | ------------------------------------------------------------------------------- |
| `resource` | yes      | The scaffold command group, e.g. `app`, `service`.                              |
| `action`   | yes      | The subcommand under that group, e.g. `create`.                                 |
| `options`  | no       | Mapping of options and positional arguments for that command. Defaults to `{}`. |

#### Q: Which resources and actions can I use in a config file?

**A:** `scaffold apply` only supports two levels — `resource` then a leaf `action` — so any scaffold subcommand nested deeper than that (like `scaffold request logs list`) can't be expressed in a config file. The complete, usable set is:

| `resource` | valid `action` values                                                                     |
| ---------- | ----------------------------------------------------------------------------------------- |
| `app`      | `create`                                                                                  |
| `service`  | `create`, `list`, `show`, `delete`, `update`                                              |
| `workflow` | `create`, `copy`, `show`, `up`, `down`, `logs`, `mkcert`, `rewrite`, `filter`, `validate` |
| `hostname` | `install`, `uninstall`                                                                    |

`apply` and `describe` aren't usable as a `resource` (they're standalone commands, not groups), and `request` is a group whose only child (`logs`) is itself a group, so it has no usable leaf action either.

#### Q: How do I translate a CLI flag into an `options` key?

**A:** Use the **snake\_case** version of the flag name — `--app-dir-path` becomes `app_dir_path`, `--copy-on-workflow-up` becomes `copy_on_workflow_up`. Positional arguments (like the app or service name) use their argument name as the key.

| Kind                                 | YAML shape                                                                      |
| ------------------------------------ | ------------------------------------------------------------------------------- |
| Flag                                 | boolean: `quiet: true`                                                          |
| Single value                         | scalar: `hostname: api.example.com`                                             |
| Multi-value option (`multiple=True`) | list: `plugin: [playwright]` (a bare scalar is also accepted as a single value) |
| Positional argument                  | key matching the argument name: `app_name: my-app`, `service_name: api`         |

An option key that doesn't exist on the target command is a validation error before anything runs.

Some frequently used options have a fixed set of accepted values:

* `app create`: `plugin: [cypress, playwright]`, `proxy_mode: [forward, reverse]`, `runtime: [docker, local]`
* `service create`: `scheme` / `upstream_scheme`: `[http, https]`, `workflow: [develop, mock, record, test]`

#### Q: Which paths get resolved automatically, and against what?

**A:** These six option keys are path-expanded: `app_dir_path`, `context_dir_path`, `script_path`, `ca_certs_dir_path`, `certs_dir_path`, `docker_socket_path`. For each, `~` is expanded first, then — if the path is still relative — it's resolved **against the config file's directory**, not your current working directory. So a relative path in `.stoobly/scaffold.yml` resolves relative to `.stoobly/`, no matter where you run `scaffold apply` from. Lists of paths (e.g. multiple `context_dir_path` entries) are expanded element-wise. All other options are passed through unchanged.

{% hint style="warning" %}
`scaffold apply` never creates directories. If an option is required to already exist (for example `context_dir_path`), the underlying command's validation will fail if it doesn't.
{% endhint %}

#### Q: Can I use JSON instead of YAML?

**A:** Yes — pass `--format json`. The schema is identical, just expressed as JSON.

**Example:**

```json
{
  "version": 1,
  "commands": [
    {
      "resource": "app",
      "action": "create",
      "options": {
        "app_name": "my-app",
        "plugin": ["playwright"]
      }
    },
    {
      "resource": "service",
      "action": "create",
      "options": {
        "service_name": "api",
        "hostname": "api.example.com",
        "scheme": "https",
        "port": 443
      }
    }
  ]
}
```

```bash
stoobly-agent scaffold apply .stoobly/scaffold.json --format json --dry-run
stoobly-agent scaffold apply .stoobly/scaffold.json --format json
```

***

### Full Example

#### Q: What does a larger, multi-service config look like?

**A:** A config can chain any number of `app`, `service`, and `workflow` steps. This example creates an app across two directories in a monorepo, adds three services (one local, one external with an OpenAPI spec, one with a custom `test` workflow), a custom `ci` workflow, and starts the `mock` workflow.

```yaml
version: 1
commands:
  - resource: app
    action: create
    options:
      app_name: monorepo
      app_dir_path: ~/monorepo
      context_dir_path:
        - ~/monorepo/apps/app-1
        - ~/monorepo/apps/app-2
      copy_on_workflow_up: true
      ui_port: 4201
      plugin: [playwright]

  - resource: service
    action: create
    options:
      service_name: dashboard
      app_dir_path: ~/monorepo
      context_dir_path:
        - ~/monorepo/apps/app-1
      hostname: local.stoobly.com
      scheme: http
      port: 80
      local: true

  - resource: service
    action: create
    options:
      service_name: google
      app_dir_path: ~/monorepo
      context_dir_path:
        - ~/monorepo/apps/app-1
        - ~/monorepo/apps/app-2
      env: [TEST]
      hostname: www.google.com
      scheme: https
      openapi_specification: true
      port: 443

  - resource: workflow
    action: create
    options:
      workflow_name: ci
      app_dir_path: ~/monorepo
      service: [google]
      template: mock

  - resource: service
    action: create
    options:
      service_name: assets
      app_dir_path: ~/monorepo
      hostname: http.badssl.com
      scheme: http
      port: 80
      detached: true
      workflow: [test]

  - resource: workflow
    action: up
    options:
      workflow_name: mock
      app_dir_path: ~/monorepo
      context_dir_path: ~/monorepo/apps/app-1
      log_level: warning
```

***

### Validation and Failure Behavior

#### Q: When does validation happen?

**A:** The **entire config is validated up front**, before any step runs — every step's `resource`, `action`, and `options` are checked. A typo in the last step means the first step never runs either; you find out immediately rather than partway through applying.

#### Q: What happens if a step fails partway through?

**A:** `scaffold apply` stops at the first failing step and exits with that step's own exit code. Steps that already ran are **not** rolled back — their side effects (files created, services registered, etc.) remain in place. Later steps in the config are not run.

#### Q: Does `--dry-run` guarantee the real apply will succeed?

**A:** Not entirely. `--dry-run` runs full config validation (schema, unknown resource/action/option, accepted values, missing required options) and logs one line per step, but it never actually invokes a command. That means checks that only happen when a command runs — like a required directory existing on disk — are **not** exercised by `--dry-run`. Treat a clean dry run as "the config itself is well-formed," not as "applying it will definitely succeed."

**Example:**

```bash
$ stoobly-agent scaffold apply .stoobly/scaffold.yml --dry-run
[INFO] Scaffold would apply app create my-app
[INFO] Scaffold would apply service create api
```

Without `--dry-run`, the same steps log as `applying …` before each one actually runs:

```bash
$ stoobly-agent scaffold apply .stoobly/scaffold.yml
[INFO] Scaffold applying app create my-app
[INFO] Scaffold applying service create api
```

{% hint style="info" %}
Only **positional** argument values (like the app or service name) are logged — option flags and their values are deliberately omitted from the log line, so nothing sensitive in `options` gets echoed. Logs go to stderr; setting `STOOBLY_AGENT_LOG_LEVEL=warning` suppresses the `applying …` / `would apply …` lines.
{% endhint %}

#### Q: What are the common validation errors, and what do they mean?

**A:** All of the following are checked before any step is invoked and exit with code `1`:

| Condition                                         | Message                                                         |
| ------------------------------------------------- | --------------------------------------------------------------- |
| Missing `version`                                 | `Missing required property: version`                            |
| Unsupported `version`                             | `Unsupported version: … Supported versions: 1`                  |
| Missing or empty `commands`                       | `commands must be a non-empty list`                             |
| Config file is empty, or its root isn't a mapping | `Config file is empty` / `Config root must be a mapping`        |
| Invalid YAML/JSON                                 | `Failed to parse config file: …`                                |
| Step missing `resource` or `action`               | `commands[i] missing required property: resource`               |
| Unknown `resource`                                | `Unknown resource: …`                                           |
| `resource` isn't a command group                  | `Resource '…' is not a command group`                           |
| Unknown `action`                                  | `Unknown action '…' for resource '…'`                           |
| `action` is a group, not a leaf command           | `Action '…' for resource '…' is a group, not a command`         |
| Unknown option key                                | `commands[i]: Unknown options for command: …`                   |
| Flag given a non-boolean value                    | `commands[i].options.… must be a boolean flag`                  |
| Value not in the accepted list                    | `commands[i].options.… has invalid value …. Accepted values: …` |
| Missing a required option/argument                | `commands[i] missing required option(s): …`                     |

A `PATH` that doesn't exist or is a directory fails Click's own argument check and exits with code `2` instead.

***

### Related

{% content-ref url="/pages/IsP4sqSmIxdC4r86BS5O" %}
[Applying a Scaffold Config](/guides/how-to-integrate-e2e-testing/how-to-scaffold-an-app/applying-a-scaffold-config)
{% endcontent-ref %}

{% content-ref url="/pages/33Q0OfLXlzbByHH9QvmZ" %}
[How to Update a Scaffold](/guides/how-to-integrate-e2e-testing/how-to-update-a-scaffold)
{% endcontent-ref %}


# Customization

## Stoobly Scaffold Structure - Questions & Answers

After scaffolding an app and services, Stoobly creates a comprehensive directory structure in `.stoobly/services/` with workflow-specific configurations, Docker compose files, and helper scripts.

**📚 Related Documentation:**

* For Docker-specific customization, see [docker.md](/faq/scaffold/customization/docker)
* For local runtime customization, see [local.md](/faq/scaffold/customization/local)

***

### Understanding Scaffold Structure

#### Q: Where does the scaffold get created?

**A:** The scaffold is created in the `.stoobly/services/` directory within your application directory.

**Example:**

```
# Create app
stoobly-agent scaffold app create my-app --app-dir-path ./my-project

# Scaffold structure created at:
# ./my-project/.stoobly/services/
```

#### Q: What is the overall structure of a scaffolded app?

**A:** The scaffold contains core services (build, entrypoint, gateway, stoobly-ui), user-defined services, a Makefile, and workflow-specific configurations.

**Example:**

```bash
.stoobly/services/
├── Makefile                    # Main Makefile for workflow commands
├── build/                      # Build service (Docker only)
│   ├── mock/
│   ├── record/
│   └── test/
├── entrypoint/                 # Entrypoint service (Docker only)
│   ├── mock/
│   ├── record/
│   └── test/
├── gateway/                    # Gateway service (Docker only)
│   ├── mock/
│   ├── record/
│   └── test/
├── stoobly-ui/                 # Stoobly UI service
│   ├── exec/
│   ├── mock/
│   └── record/
└── your-service/               # Your custom services
    ├── mock/
    ├── record/
    └── test/
```

***

### Docker vs Local Runtime Differences

#### Q: What's the difference between --runtime docker and --runtime local?

**A:** Docker runtime creates additional core services (build, entrypoint, gateway) for containerized execution, while local runtime creates a simpler structure for native execution.

**Example:**

```bash
# Docker runtime (default) - Full container orchestration
stoobly-agent scaffold app create my-app --runtime docker

# Creates:
# - build/ (Docker image building)
# - entrypoint/ (Container entry point)
# - gateway/ (Traefik reverse proxy)
# - stoobly-ui/ (UI service)
# - your-services/

# Local runtime - Simplified structure
stoobly-agent scaffold app create my-app --runtime local

# Creates:
# - stoobly-ui/ (UI service)
# - your-services/ (only user services)
# No build/, entrypoint/, or gateway/ directories
```

**For more details:**

* Docker-specific topics: See [docker.md](/faq/scaffold/customization/docker)
* Local-specific topics: See [local.md](/faq/scaffold/customization/local)

***

### Understanding Core Services

#### Q: What is the stoobly-ui service?

**A:** The stoobly-ui service provides the web interface for managing requests, scenarios, and configuration. It's available in both Docker and local runtimes.

**Example:**

```bash
.stoobly/services/stoobly-ui/
├── exec/                       # For CLI execution
├── mock/                       # UI for mock workflow
└── record/                     # UI for record workflow

# Access UI at: http://localhost:4200
```

**Note:** For Docker-specific services (build, entrypoint, gateway), see [docker.md](/faq/scaffold/customization/docker).

***

### Service-Specific Directories

#### Q: What files are created for each user-defined service?

**A:** Each service gets workflow directories (mock, record, test) with an init script, lifecycle hooks, fixtures, and public directory. Docker runtime also includes docker-compose.yml files.

**Example:**

```bash
.stoobly/services/my-service/
├── mock/
│   ├── docker-compose.yml      # Service definition (Docker only)
│   ├── fixtures.yml            # Response fixtures
│   ├── init                    # Init script
│   ├── lifecycle_hooks.py      # Custom hooks
│   └── public/                 # Static files
├── record/
│   ├── docker-compose.yml      # (Docker only)
│   ├── init
│   └── lifecycle_hooks.py
└── test/
    ├── docker-compose.yml      # (Docker only)
    ├── fixtures.yml
    ├── init
    ├── lifecycle_hooks.py
    └── public/
```

#### Q: Where do I add Stoobly configuration (rewrite, match, filter rules)?

**A:** Add Stoobly configuration in the workflow `init` script so rules are applied before services start.

**Example:**

```bash
# .stoobly/services/my-service/mock/init
#!/bin/bash

# Add rewrite rules
stoobly-agent setting rewrite set \
  --pattern "https://api.production.com/.*" \
  --method GET --method POST \
  --mode mock \
  --hostname localhost:8080

# Add filter rules
stoobly-agent setting filter set \
  --pattern "https://analytics.com/.*" \
  --method GET \
  --mode mock \
  --action exclude
```

#### Q: What is the purpose of the init script?

**A:** The init script runs custom initialization logic during service startup, such as database setup, file preparation, or environment checks.

**Example:**

```bash
# .stoobly/services/my-service/mock/init
#!/bin/bash

# Wait for dependencies
sleep 2

# Setup test data
echo "Initializing test data..."
curl -X POST http://my-service/setup

# Verify service health
curl http://my-service/health
```

**Note:** For Docker-specific docker-compose.yml customization, see [docker.md](/faq/scaffold/customization/docker).

#### Q: What is the fixtures.yml file used for?

**A:** The fixtures.yml file contains mock response data for the service, used during mock and test workflows.

**Example:**

```yaml
# .stoobly/services/my-service/mock/fixtures.yml
- GET:
  /users/d+?:
    headers: {}
    path: <RELATIVE-PATH-TO-TO-RESPONSE-FILE>
    status_code: 200
- POST:
  /users:
    headers: {}
    path: <RELATIVE-PATH-TO-TO-RESPONSE-FILE>
    status_code: 200
```

#### Q: What is the lifecycle\_hooks.py file used for?

**A:** The lifecycle\_hooks.py file contains Python functions that modify requests/responses during interception.

**Example:**

```python
# .stoobly/services/my-service/mock/lifecycle_hooks.py

def before_request(context):
    # Modify request before sending
    context.request.headers['X-Custom-Header'] = 'test-value'
    return context

def after_response(context):
    # Modify response before returning
    if context.response.status_code == 404:
        context.response.status_code = 200
    return context
```

#### Q: What is the public/ directory used for?

**A:** The public/ directory serves static files for mocking, useful for serving images, CSS, JavaScript, or other assets.

**Example:**

```bash
# .stoobly/services/my-service/mock/public/
mkdir -p .stoobly/services/my-service/mock/public
echo '{"data": "test"}' > .stoobly/services/my-service/mock/public/test.json

# Access via: http://my-service.local/test.json
```

***

### Workflow-Specific Configurations

#### Q: How are workflows organized?

**A:** Each service has separate directories for mock, record, and test workflows, allowing different configurations per workflow.

**Example:**

```bash
my-service/
├── mock/                       # Mock workflow config
│   ├── fixtures.yml           # Mock responses
│   └── docker-compose.yml     # Mock-specific settings
├── record/                     # Record workflow config
│   └── docker-compose.yml     # Record-specific settings
└── test/                       # Test workflow config
    ├── fixtures.yml           # Test fixtures
    └── docker-compose.yml     # Test-specific settings
```

#### Q: Can I have different configurations for different workflows?

**A:** Yes, each workflow directory has its own `init` script, `docker-compose.yml` (Docker only), and fixtures, allowing complete customization per workflow.

**Example:**

```bash
# Mock workflow - Use local fixtures
# .stoobly/services/my-service/mock/init
stoobly-agent setting rewrite set --mode mock --hostname localhost

# Record workflow - Use production
# .stoobly/services/my-service/record/init
stoobly-agent setting rewrite set --mode record --hostname api.production.com

# Test workflow - Use staging
# .stoobly/services/my-service/test/init
stoobly-agent setting rewrite set --mode test --hostname api.staging.com
```

***

### Custom Workflows

#### Q: How do I create a custom workflow?

**A:** Use `scaffold workflow create` to create a new workflow based on a template (mock, record, or test).

**Example:**

```bash
# Create custom 'ci' workflow for a service
stoobly-agent scaffold workflow create ci \
  --template mock \
  --service my-service \
  --app-dir-path ./my-app

# Creates:
# .stoobly/services/my-service/ci/
```

#### Q: What gets created for a custom workflow?

**A:** A custom workflow gets the same structure as standard workflows: docker-compose.yml, init, fixtures.yml, lifecycle\_hooks.py, and public/.

**Example:**

```bash
.stoobly/services/my-service/ci/
├── docker-compose.yml
├── fixtures.yml
├── init
├── lifecycle_hooks.py
└── public/
```

***

### Temporary Runtime Files

#### Q: What is the .stoobly/tmp/ directory?

**A:** The tmp/ directory contains runtime files generated during workflow execution, including logs, run scripts, and Traefik configuration.

**Example:**

```bash
.stoobly/tmp/
├── mock/
│   ├── logs/
│   │   └── requests.json       # Request logs
│   ├── run.sh                  # Generated run script
│   └── traefik.yml             # Traefik config
├── record/
│   └── ...
└── test/
    └── ...
```

**Note:** For Docker-specific run.sh script details, see [docker.md](/faq/scaffold/customization/docker).

***

### Troubleshooting

#### Q: How do I debug scaffold issues?

**A:** Check the generated files in .stoobly/services/ and .stoobly/tmp/, and use --dry-run to see what commands would execute.

**Example:**

```bash
# Dry run to see commands
stoobly-agent scaffold workflow up mock --dry-run --app-dir-path ./my-app

# Check generated run script
cat .stoobly/tmp/mock/run.sh

# Check logs
cat .stoobly/tmp/mock/logs/requests.json
```

#### Q: Where can I find workflow logs?

**A:** Workflow logs are stored in `.stoobly/tmp/<workflow>/logs/`.

**Example:**

```bash
# View request logs
cat .stoobly/tmp/mock/logs/requests.json
```

**Note:** For Docker-specific log viewing, see [docker.md](/faq/scaffold/customization/docker).

#### Q: How do I verify my service configuration?

**A:** Run the init script manually (if applicable) and verify Stoobly configuration.

**Example:**

```bash
# Run init script
bash .stoobly/services/my-service/mock/init

# Verify Stoobly config
stoobly-agent setting dump
```

**Note:** For Docker-specific configuration verification, see [docker.md](/faq/scaffold/customization/docker).

***

### Quick Reference

#### Q: What are the key directories in a scaffold?

**A:** Here's a quick reference of important directories:

**Example:**

```bash
.stoobly/services/
├── Makefile                    # Main workflow commands
├── build/                      # Docker: Image building (Docker only)
├── entrypoint/                 # Docker: Your app runs here (Docker only)
├── gateway/                    # Docker: Traefik proxy (Docker only)
├── stoobly-ui/                 # Stoobly web UI (Both)
├── your-service/               # Your services (Both)
│   ├── mock/                   # Mock workflow
│   ├── record/                 # Record workflow
│   └── test/                   # Test workflow
└── .stoobly/tmp/               # Runtime files (Both)
    ├── mock/
    ├── record/
    └── test/
```

#### Q: What files can I customize?

**A:** You can customize init scripts, fixtures.yml, lifecycle\_hooks.py, and add files to public/. For Docker runtime, you can also customize docker-compose.yml files.

**Example:**

```bash
# Customizable files per service/workflow:
my-service/mock/
├── docker-compose.yml      # ✓ Add your containers (Docker only)
├── fixtures.yml            # ✓ Add mock responses
├── init                    # ✓ Add initialization logic
├── lifecycle_hooks.py      # ✓ Add request/response hooks
└── public/                 # ✓ Add static files
```

**For more details:**

* Docker-specific customization: See [docker.md](/faq/scaffold/customization/docker)
* Local runtime customization: See [local.md](/faq/scaffold/customization/local)


# Docker

## Stoobly Scaffold Docker Runtime - Questions & Answers

This document covers Docker-specific customization options for Stoobly scaffold. For general customization topics, see [README.md](/faq/scaffold/customization). For local runtime customization, see [local.md](/faq/scaffold/customization/local).

***

### Docker Runtime Structure

#### Q: Which files are created for Docker runtime only?

**A:** Docker runtime creates build/, entrypoint/, and gateway/ service directories with Docker Compose configurations.

**Example:**

```bash
# Docker-only services:
.stoobly/services/
├── build/                      # Docker only
├── entrypoint/                 # Docker only
├── gateway/                    # Docker only
└── stoobly-ui/                 # Both Docker and local
```

***

### Understanding the Entrypoint Service

#### Q: What is the entrypoint service?

**A:** The entrypoint service is the main container that runs your application or test code within the Docker network. It's where your actual service or test scripts execute.

**Example:**

```bash
# Entrypoint service structure
.stoobly/services/entrypoint/
├── mock/
│   ├── docker-compose.yml      # Service definition
│   ├── init                    # Initialization script
│   └── run                     # Entrypoint script
├── record/
│   ├── docker-compose.yml
│   ├── init
│   └── run
└── test/
    ├── docker-compose.yml
    ├── init
    └── run
```

#### Q: What is the purpose of the entrypoint service?

**A:** The entrypoint service provides a containerized environment where your application runs and makes HTTP requests that get intercepted by Stoobly's proxy through the gateway.

**Example:**

```bash
# Workflow flow:
# 1. Entrypoint container starts
# 2. Your app/tests run inside entrypoint
# 3. HTTP requests go through gateway (Traefik)
# 4. Gateway routes to Stoobly proxy
# 5. Stoobly records/mocks/tests the requests
```

#### Q: When is the entrypoint service used?

**A:** The entrypoint service is used in Docker runtime workflows to run your application code, test suites, or any process that makes HTTP requests you want to intercept.

**Example:**

```bash
# Start mock workflow
make -f .stoobly/services/Makefile mock

# Entrypoint container runs your app
# App makes requests → Gateway → Stoobly proxy → Mocked responses
```

#### Q: How do I customize the entrypoint service?

**A:** Edit the `docker-compose.yml` file in the entrypoint workflow directory to add your application container, environment variables, or volumes.

**Example:**

```yaml
# .stoobly/services/entrypoint/mock/docker-compose.yml
services:
  entrypoint.my-app:
    image: my-app:latest
    depends_on:
      entrypoint.init:
        condition: service_completed_successfully
    networks:
      app.ingress: {}
    environment:
      - HTTP_PROXY=http://gateway:80
      - HTTPS_PROXY=http://gateway:80
    profiles:
      - ${WORKFLOW_NAME}
    command: npm test
```

***

### Understanding Docker Core Services

#### Q: What is the build service?

**A:** The build service creates the Docker image for Stoobly agent with your application's context, ensuring consistent environments across workflows.

**Example:**

```bash
.stoobly/services/build/
├── mock/
│   ├── init
│   ├── docker-compose.yml      # Builds stoobly image
│   └── init
└── ...
```

#### Q: What is the gateway service?

**A:** The gateway service runs Traefik reverse proxy that routes HTTP traffic from your services through Stoobly's proxy for interception.

**Example:**

```bash
.stoobly/services/gateway/
├── mock/
│   └── docker-compose.yml      # Traefik configuration
└── ...

# Gateway routes:
# your-service:80 → gateway:80 → stoobly-proxy:8080 → upstream
```

***

### Docker-Specific Customization

#### Q: How do I add my application to the entrypoint service?

**A:** Edit the entrypoint docker-compose.yml to include your application container.

**Example:**

```yaml
# .stoobly/services/entrypoint/test/docker-compose.yml
services:
  entrypoint.my-app:
    image: node:18
    working_dir: /app
    volumes:
      - ../../..:/app
    depends_on:
      entrypoint.init:
        condition: service_completed_successfully
    networks:
      app.ingress: {}
    environment:
      - HTTP_PROXY=http://gateway:80
      - HTTPS_PROXY=http://gateway:80
      - NO_PROXY=localhost,127.0.0.1
    profiles:
      - ${WORKFLOW_NAME}
    command: npm test
```

#### Q: How do I run my test suite in the entrypoint?

**A:** Configure the entrypoint service with your test command and ensure it uses the proxy.

**Example:**

```yaml
# .stoobly/services/entrypoint/test/docker-compose.yml
services:
  entrypoint.playwright-tests:
    image: mcr.microsoft.com/playwright:latest
    working_dir: /tests
    volumes:
      - ../../..:/tests
    depends_on:
      entrypoint.init:
        condition: service_completed_successfully
    networks:
      app.ingress: {}
    environment:
      - HTTP_PROXY=http://gateway:80
      - HTTPS_PROXY=http://gateway:80
    profiles:
      - ${WORKFLOW_NAME}
    command: npx playwright test
```

#### Q: How do I add environment variables to my Docker service?

**A:** Add environment variables in the docker-compose.yml file for your service.

**Example:**

```yaml
# .stoobly/services/my-service/mock/docker-compose.yml
services:
  my-service.app:
    environment:
      - DATABASE_URL=postgres://localhost/testdb
      - API_KEY=test-key-123
      - NODE_ENV=test
      - DEBUG=true
```

#### Q: How do I mount volumes for my Docker service?

**A:** Add volume mounts in the docker-compose.yml to share files between host and container.

**Example:**

```yaml
# .stoobly/services/my-service/mock/docker-compose.yml
services:
  my-service.app:
    volumes:
      - ../../..:/app                    # Mount project root
      - ./fixtures.yml:/app/fixtures.yml # Mount fixtures
      - ./public:/app/public             # Mount public files
```

#### Q: What is the docker-compose.yml file used for?

**A:** The docker-compose.yml defines the service container, its dependencies, networks, environment variables, and how it connects to other services.

**Example:**

```yaml
# .stoobly/services/my-service/mock/docker-compose.yml
services:
  my-service.proxy:
    depends_on:
      my-service.init:
        condition: service_completed_successfully
    environment:
      - STOOBLY_HOSTNAME=my-service.local
      - STOOBLY_UPSTREAM_HOSTNAME=api.production.com
    networks:
      app.ingress: {}
    profiles:
      - ${WORKFLOW_NAME}
```

#### Q: How do I use a custom context directory?

**A:** Set the `STOOBLY_CONTEXT_DIR` environment variable to your desired context directory before running Makefile commands.

**Example:**

```bash
export STOOBLY_CONTEXT_DIR=/path/to/context
make -f .stoobly/services/Makefile test
```

#### Q: How do I run workflows with custom namespaces?

**A:** Use the `namespace` variable to specify a custom workflow namespace when running Makefile commands.

**Note:** Namespaces are only supported by test workflows and custom workflows based on the test workflow template. Record and mock workflows do not support namespaces.

**Example:**

```bash
make -f .stoobly/services/Makefile test namespace=my-custom-namespace
```

#### Q: How do I run workflows in dry-run mode?

**A:** Use the `--dry-run` flag with the CLI command to see what commands would be executed without running them.

**Example:**

```bash
stoobly-agent scaffold workflow up test --dry-run
```

***

### Advanced Configuration

#### Q: How do I increase logging verbosity?

**A:** Use the make logs command with options to control logging verbosity. You can also set the `workflow_log_extra_options` variable to pass additional options.

**Example:**

```bash
# View logs for a workflow
make -f .stoobly/services/.Makefile record/logs

# View logs with options (check available options with -h)
make -f .stoobly/services/.Makefile record/logs options="-h"

# View logs for specific containers
make -f .stoobly/services/.Makefile record/logs options="--container init"

# Set extra log options globally
make -f .stoobly/services/.Makefile record/logs workflow_log_extra_options="--tail=100"
```

#### Q: How do I follow workflow logs in real-time?

**A:** Use the make logs command with the `-f` / `--follow` option to stream logs continuously.

**Example:**

```bash
# Follow logs for a workflow
make -f .stoobly/services/.Makefile record/logs options="--follow"

# Follow logs for specific containers
make -f .stoobly/services/.Makefile record/logs options="--follow --container service --service gateway"

# Follow logs for specific service
make -f .stoobly/services/.Makefile record/logs options="--follow --service api"
```

***

### Docker Troubleshooting

#### Q: How do I view Docker logs for my services?

**A:** Use docker-compose logs to view container output.

**Example:**

```bash
# View Docker logs
docker-compose -f .stoobly/services/my-service/mock/docker-compose.yml logs

# View logs for specific service
docker-compose -f .stoobly/services/my-service/mock/docker-compose.yml logs my-service.proxy

# Follow logs in real-time
docker-compose -f .stoobly/services/my-service/mock/docker-compose.yml logs -f
```

#### Q: What is the run.sh script?

**A:** The run.sh script is auto-generated by the scaffold workflow up command and contains the Docker Compose commands to start the workflow.

**Example:**

```bash
# Generated run.sh
#!/bin/bash
docker-compose -f .stoobly/services/build/mock/docker-compose.yml up
docker-compose -f .stoobly/services/gateway/mock/docker-compose.yml up -d
docker-compose -f .stoobly/services/my-service/mock/docker-compose.yml up -d
# ... more services
```


# Local

## Stoobly Scaffold Local Runtime - Questions & Answers

This document covers local runtime-specific customization options for Stoobly scaffold. For general customization topics, see [README.md](/faq/scaffold/customization). For Docker runtime customization, see [docker.md](/faq/scaffold/customization/docker).

***

### Local Runtime Structure

#### Q: Which files are created for both Docker and local runtime?

**A:** Both runtimes create the Makefile, stoobly-ui service, and user-defined service directories.

**Example:**

```bash
# Common to both:
.stoobly/services/
├── Makefile                    # Both
├── stoobly-ui/                 # Both
└── your-service/               # Both
```

#### Q: What's the difference between --runtime docker and --runtime local?

**A:** Docker runtime creates additional core services (build, entrypoint, gateway) for containerized execution, while local runtime creates a simpler structure for native execution.

**Example:**

```bash
# Local runtime - Simplified structure
stoobly-agent scaffold app create my-app --runtime local

# Creates:
# - stoobly-ui/ (UI service)
# - your-services/ (only user services)
# No build/, entrypoint/, or gateway/ directories
```

**Note:** With local runtime, your services run natively on your machine rather than in containers. You'll need to configure your applications to use Stoobly's proxy directly.

***

### Local Runtime Customization

#### Q: How do I configure my application to use Stoobly with local runtime?

**A:** Configure your application to use Stoobly's proxy by setting HTTP\_PROXY and HTTPS\_PROXY environment variables, or by configuring your application's HTTP client to use the proxy.

**Example:**

```bash
# Set proxy environment variables
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080

# Run your application
npm start
```

#### Q: How do I add environment variables for local runtime?

**A:** For local runtime, set environment variables in your shell or use a `.env` file that your application reads. Unlike Docker runtime, there's no docker-compose.yml to configure.

**Example:**

```bash
# Set environment variables before running
export DATABASE_URL=postgres://localhost/testdb
export API_KEY=test-key-123
export NODE_ENV=test

# Or use a .env file
cat > .env << EOF
DATABASE_URL=postgres://localhost/testdb
API_KEY=test-key-123
NODE_ENV=test
EOF
```

#### Q: How do I run tests with local runtime?

**A:** Run your tests directly with proxy environment variables set, or configure your test framework to use Stoobly's proxy.

**Example:**

```bash
# Set proxy and run tests
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080
npx playwright test

# Or configure in your test config
# playwright.config.ts
export default defineConfig({
  use: {
    proxy: {
      server: 'http://localhost:8080',
    },
  },
});
```

#### Q: How do I use a custom context directory?

**A:** Use the `--context-dir-path` option when running workflow commands to specify a custom Stoobly data directory.

**Example:**

```bash
stoobly-agent scaffold workflow up test --context-dir-path /path/to/custom/.stoobly
```

#### Q: How do I run workflows with custom namespaces?

**A:** Use the `--namespace` option to specify a custom workflow namespace when running workflow commands.

**Note:** Namespaces are only supported by test workflows and custom workflows based on the test workflow template. Record and mock workflows do not support namespaces.

**Example:**

```bash
stoobly-agent scaffold workflow up test --namespace my-custom-namespace
```

#### Q: How do I run workflows in dry-run mode?

**A:** Use the `--dry-run` flag to see what commands would be executed without running them.

**Example:**

```bash
stoobly-agent scaffold workflow up test --dry-run
```

#### Q: What's the difference between init and run scripts?

**A:** The `init` script runs before services start to set up Stoobly configuration, while `run` script runs after init completes.

**Example:**

```bash
# init script - Runs first
# .stoobly/services/entrypoint/mock/init
#!/bin/bash
# Add custom Stoobly configuration here
stoobly-agent setting rewrite set --pattern "..." --hostname localhost

# run script - Runs after container init
# Custom entrypoint logic
```

***

### Advanced Configuration

#### Q: How do I increase logging verbosity?

**A:** Use the `--log-level` option when starting a workflow to set the logging level.

**Example:**

```bash
stoobly-agent scaffold workflow up test --log-level debug
```

#### Q: How do I follow workflow logs in real-time?

**A:** Use the `-f` / `--follow` flag with the scaffold workflow logs command to stream logs continuously.

**Example:**

```bash
stoobly-agent scaffold workflow logs record --follow
```

***

### Local Runtime Troubleshooting

#### Q: How do I verify my local service configuration?

**A:** Check the service's init script and run it manually if needed, then verify Stoobly configuration.

**Example:**

```bash
# View service init script
cat .stoobly/services/my-service/mock/init

# Run init script
bash .stoobly/services/my-service/mock/init

# Verify Stoobly config
stoobly-agent setting dump
```

#### Q: How do I view intercepted request logs for a workflow?

**A:** Use the `stoobly-agent scaffold request logs list` command to inspect intercepted request logs for a workflow.

**Examples:**

```bash
# List intercepted request log entries for a workflow
stoobly-agent scaffold request logs list record
stoobly-agent scaffold request logs list mock
stoobly-agent scaffold request logs list test

# Follow logs in real time (-f / --follow, Ctrl-C to stop)
stoobly-agent scaffold request logs list test --follow

# Filter by service name
stoobly-agent scaffold request logs list mock --service-name my-service

# Filter by namespace
stoobly-agent scaffold request logs list mock --namespace my-namespace

# Filter by HTTP method
stoobly-agent scaffold request logs list test --method post

# Filter by URL substring
stoobly-agent scaffold request logs list mock --url /api/users

# Filter by HTTP status code
stoobly-agent scaffold request logs list test --status-code 500

# Filter by log level
stoobly-agent scaffold request logs list test --level error

# Filter by log message
stoobly-agent scaffold request logs list mock --message "Mock failure"

# Filter by scenario name
stoobly-agent scaffold request logs list mock --scenario-name my-scenario

# Output as JSON
stoobly-agent scaffold request logs list mock --format json

# Select specific columns
stoobly-agent scaffold request logs list test --select method,url,status-code

# Combine filters with follow
stoobly-agent scaffold request logs list test --follow --level error --method post

# Use a custom context directory
stoobly-agent scaffold request logs list mock \
  --context-dir-path /path/to/custom/.stoobly
```

#### Q: How do I find the log file path for a workflow?

**A:** Use the `stoobly-agent scaffold request logs path` command to print the underlying intercepted request log file path for a workflow.

**Example:**

```bash
stoobly-agent scaffold request logs path mock
stoobly-agent scaffold request logs path test
```

#### Q: How do I delete intercepted request logs for a workflow?

**A:** Use the `stoobly-agent scaffold request logs delete` command to truncate (delete) intercepted request logs for a workflow.

**Example:**

```bash
stoobly-agent scaffold request logs delete mock
stoobly-agent scaffold request logs delete test
```


# E2E Testing

## Stoobly Scaffold E2E Testing - Questions & Answers

Stoobly scaffold provides first-class support for E2E testing frameworks like Playwright and Cypress, enabling you to record, mock, and validate API interactions during your end-to-end tests.

**📚 Related Documentation:**

* For Docker-specific E2E testing, see [docker.md](/faq/scaffold/e2e-testing/docker)
* For local runtime E2E testing, see [local.md](/faq/scaffold/e2e-testing/local)
* For using the JavaScript client library, see [js-client/](/faq/scaffold/e2e-testing/js-client)

**⚠️ Important:** Make commands (e.g., `make -f .stoobly/services/Makefile test`) are **Docker-specific only**. Local runtime uses CLI commands directly (e.g., `stoobly-agent scaffold workflow up test`).

***

### Plugin Support

#### Q: What E2E testing frameworks does Stoobly support?

**A:** Stoobly supports **Playwright** and **Cypress** through the `--plugin` option when creating an app.

**Example:**

```bash
# Create app with Playwright support
stoobly-agent scaffold app create my-app --plugin playwright

# Create app with Cypress support
stoobly-agent scaffold app create my-app --plugin cypress

# Create app with both plugins
stoobly-agent scaffold app create my-app --plugin playwright --plugin cypress
```

**Note:** The files created depend on whether you use `--runtime docker` or `--runtime local`. For Docker-specific file details, see [docker.md](/faq/scaffold/e2e-testing/docker). For local runtime setup, see [local.md](/faq/scaffold/e2e-testing/local).

***

### Frontend Service Setup

#### Q: How do I set up a frontend service to serve static assets for E2E tests?

**A:** Frontend services typically only need the `test` workflow since they serve static assets from fixtures rather than recording or mocking requests. Create the service with `--workflow test` and modify the `test/init` script to copy your built application to the public fixtures folder.

**Example:**

```bash
# Create frontend service with only test workflow
stoobly-agent scaffold service create frontend \
  --hostname app.local \
  --port 80 \
  --scheme http \
  --workflow test
```

**Modify the init script to copy built assets:**

```bash
# .stoobly/services/frontend/test/init
#!/bin/bash

# Copy built frontend assets to public fixtures folder
# This makes the application available for E2E tests
cp -r ./dist/. .stoobly/fixtures/public/

# The frontend service will serve these static files during E2E tests
```

**Why only test workflow?**

* Frontend services serve static assets, not dynamic API responses
* No need to record requests (no API logic to capture)
* No need to mock responses (serving files, not making requests)
* Test workflow is needed so E2E tests can request the application under test

***

### Configuration Files

#### Q: What files should I modify to add my Playwright tests?

**A:** The files you modify depend on your runtime:

* **Docker runtime:** Modify entrypoint docker-compose.yml, init script, and Playwright config. See [docker.md](/faq/scaffold/e2e-testing/docker) for details.
* **Local runtime:** Configure Playwright to use Stoobly's proxy via environment variables or config. See [local.md](/faq/scaffold/e2e-testing/local) for details.
* **Using JavaScript library:** Use the Stoobly JavaScript client library with Playwright interceptor. See [js-client/](/faq/scaffold/e2e-testing/js-client) for details.

#### Q: What files should I modify to add my Cypress tests?

**A:** The files you modify depend on your runtime:

* **Docker runtime:** Modify entrypoint docker-compose.yml and Cypress config. See [docker.md](/faq/scaffold/e2e-testing/docker) for details.
* **Local runtime:** Configure Cypress to use Stoobly's proxy via environment variables or config. See [local.md](/faq/scaffold/e2e-testing/local) for details.
* **Using JavaScript library:** Use the Stoobly JavaScript client library with Cypress interceptor. See [js-client/](/faq/scaffold/e2e-testing/js-client) for details.

#### Q: How do I add custom npm packages for my tests?

**A:** The approach depends on your runtime:

* **Docker runtime:** Use custom Docker images with `PLAYWRIGHT_IMAGE` or `CYPRESS_IMAGE` environment variables. See [docker.md](/faq/scaffold/e2e-testing/docker) for details.
* **Local runtime:** Install packages directly in your project using npm/yarn. No special configuration needed.

#### Q: How do I pass environment variables to my tests?

**A:** The approach depends on your runtime:

* **Docker runtime:** Add environment variables in docker-compose.yml. See [docker.md](/faq/scaffold/e2e-testing/docker) for details.
* **Local runtime:** Set environment variables in your shell or use a `.env` file. See [local.md](/faq/scaffold/e2e-testing/local) for details.

***

### Running E2E Tests

#### Q: How do I record E2E test traffic?

**A:** Use the record workflow to capture all HTTP requests made during your E2E tests.

* **Docker runtime:** See [docker.md](/faq/scaffold/e2e-testing/docker) for Makefile commands.
* **Local runtime:** See [local.md](/faq/scaffold/e2e-testing/local) for CLI commands.

#### Q: How do I run E2E tests with mocked responses?

**A:** Use the mock workflow to run tests against recorded responses without hitting real APIs.

* **Docker runtime:** See [docker.md](/faq/scaffold/e2e-testing/docker) for Makefile commands.
* **Local runtime:** See [local.md](/faq/scaffold/e2e-testing/local) for CLI commands.

#### Q: How do I run E2E tests with response validation?

**A:** Use the test workflow to validate that responses match expected results.

* **Docker runtime:** See [docker.md](/faq/scaffold/e2e-testing/docker) for Makefile commands — the entrypoint container runs your test command automatically.
* **Local runtime:** See [local.md](/faq/scaffold/e2e-testing/local) for CLI commands. Local runtime does **not** run your tests for you — `workflow up test` only starts the proxy; you invoke Playwright/Cypress yourself afterward. To avoid the manual multi-step dance (and to get correct pass/fail exit codes in CI), wrap `workflow up`/`down` and your test command into `package.json` scripts — see [JS Client — npm Scripts](/faq/scaffold/e2e-testing/js-client/npm-scripts).

#### Q: How do I run specific test files or suites?

**A:** The approach depends on your runtime:

* **Docker runtime:** Modify the command in docker-compose.yml. See [docker.md](/faq/scaffold/e2e-testing/docker) for details.
* **Local runtime:** Use your test framework's command-line options. See [local.md](/faq/scaffold/e2e-testing/local) for details.

***

### Debugging

#### Q: How do I view test output and logs?

**A:** The approach depends on your runtime:

* **Docker runtime:** Use Makefile logs commands. See [docker.md](/faq/scaffold/e2e-testing/docker) for details.
* **Local runtime:** View logs from the workflow directory or Stoobly agent. See [local.md](/faq/scaffold/e2e-testing/local) for details.

#### Q: How do I debug failing tests?

**A:** The approach depends on your runtime:

* **Docker runtime:** Enable headed mode and increase logging verbosity in docker-compose.yml. See [docker.md](/faq/scaffold/e2e-testing/docker) for details.
* **Local runtime:** Enable debug mode in your test framework. See [local.md](/faq/scaffold/e2e-testing/local) for details.

#### Q: How do I save test artifacts (screenshots, videos)?

**A:** The approach depends on your runtime:

* **Docker runtime:** Mount an artifacts directory and configure your test framework. See [docker.md](/faq/scaffold/e2e-testing/docker) for details.
* **Local runtime:** Configure your test framework to save artifacts to a local directory. See [local.md](/faq/scaffold/e2e-testing/local) for details.

***

### Advanced Configuration

#### Q: How do I mount test fixtures and data?

**A:** The approach depends on your runtime:

* **Docker runtime:** Add volume mounts to share fixtures between host and container. See [docker.md](/faq/scaffold/e2e-testing/docker) for details.
* **Local runtime:** Reference fixtures and test data using relative paths from your project root. See [local.md](/faq/scaffold/e2e-testing/local) for details.

#### Q: How do I handle dynamic data in E2E tests?

**A:** Use Stoobly's rewrite rules to normalize dynamic values in the init script. This applies to both Docker and local runtimes.

**Example:**

```bash
# .stoobly/services/entrypoint/test/init (Docker)
# or .stoobly/services/<service>/test/init (Local)
#!/bin/bash

# Replace dynamic user IDs with fixed test ID
stoobly-agent setting rewrite set \
  --pattern "https://api.local/users/.*" \
  --method GET \
  --mode test \
  --type response_param \
  --name "userId" \
  --value "test-user-123"

# Replace timestamps
stoobly-agent setting rewrite set \
  --pattern "https://api.local/.*" \
  --method GET --method POST \
  --mode test \
  --type response_param \
  --name "timestamp" \
  --value "2024-01-01T00:00:00Z"
```

***

### Best Practices

#### Q: Should I record once and mock for all subsequent runs?

**A:** Yes, this is the recommended approach for fast, reliable E2E tests that don't depend on external APIs.

* **Docker runtime:** See [docker.md](/faq/scaffold/e2e-testing/docker) for the complete workflow example.
* **Local runtime:** See [local.md](/faq/scaffold/e2e-testing/local) for the complete workflow example.

#### Q: How do I organize E2E tests by feature?

**A:** Create separate services or custom workflows for different test suites.

* **Docker runtime:** See [docker.md](/faq/scaffold/e2e-testing/docker) for examples.
* **Local runtime:** See [local.md](/faq/scaffold/e2e-testing/local) for examples.

***

### CI/CD Integration

#### Q: Which runtime should I use in CI/CD for E2E testing?

**A:** Docker is recommended for CI/CD as it provides consistent, isolated environments. Local runtime can also be used if your CI environment has Python and stoobly-agent installed.

* **Docker runtime:** See [docker.md](/faq/scaffold/e2e-testing/docker) for CI/CD examples.
* **Local runtime:** See [local.md](/faq/scaffold/e2e-testing/local) for CI/CD examples.

#### Q: How do I test with different runtimes in CI/CD?

**A:** Create separate CI jobs, each using the desired runtime.

**Example:**

```yaml
# .github/workflows/test.yml
name: Test Different Runtimes

jobs:
  test-docker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Test with Docker
        run: |
          make -f .stoobly/services/.Makefile test
          make -f .stoobly/services/.Makefile test/down

  test-local:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install stoobly-agent
        run: pipx install stoobly-agent
      - name: Test with Local
        run: |
          stoobly-agent scaffold workflow up test
          stoobly-agent scaffold workflow down test
```

***

### Complete Examples

#### Q: What's a complete example of setting up Playwright E2E tests?

**A:** Complete examples are available for both runtimes:

* **Docker runtime:** See [docker.md](/faq/scaffold/e2e-testing/docker) for a complete Docker-based example.
* **Local runtime:** See [local.md](/faq/scaffold/e2e-testing/local) for local runtime setup guidance.
* **JavaScript library:** See [js-client/](/faq/scaffold/e2e-testing/js-client) for complete Playwright integration examples.

#### Q: How do I use the Stoobly JavaScript client library in my tests?

**A:** Install the `stoobly` package and use the Playwright or Cypress interceptor to record, mock, and test API requests directly from your test framework. See [js-client/](/faq/scaffold/e2e-testing/js-client) for installation, integration, and complete examples.

***

### Quick Reference

**Key files to modify for E2E testing:**

* **Docker runtime:** See [docker.md](/faq/scaffold/e2e-testing/docker) for file structure and customization details.
* **Local runtime:** See [local.md](/faq/scaffold/e2e-testing/local) for file structure and customization details.

**Common commands:**

* **Docker runtime (Makefile commands):** See [docker.md](/faq/scaffold/e2e-testing/docker) for complete command reference.
* **Local runtime (CLI commands):** See [local.md](/faq/scaffold/e2e-testing/local) for complete command reference.

**For more details:**

* Docker-specific customization: See [docker.md](/faq/scaffold/e2e-testing/docker)
* Local runtime customization: See [local.md](/faq/scaffold/e2e-testing/local)
* JavaScript client library: See [js-client/](/faq/scaffold/e2e-testing/js-client)


# Docker

## Stoobly Scaffold Docker Runtime E2E Testing - Questions & Answers

This document covers Docker-specific E2E testing customization options for Stoobly scaffold. For general E2E testing topics, see [README.md](/faq/scaffold/e2e-testing). For local runtime E2E testing, see [local.md](/faq/scaffold/e2e-testing/local).

***

### Docker Plugin Support

#### Q: What files are created when I use the --plugin option with Docker runtime?

**A:** When you specify a plugin with Docker runtime, Stoobly creates a custom Dockerfile and entrypoint script in the `entrypoint/test/` directory specifically configured for that E2E framework.

**Files created for Playwright:**

* `.stoobly/services/entrypoint/test/.Dockerfile.playwright` - Stoobly-maintained base image that pulls in the stock Playwright image (override via `PLAYWRIGHT_IMAGE`)
* `.stoobly/services/entrypoint/test/.entrypoint.sh` - Entrypoint script with CA certificate setup
* `.stoobly/services/entrypoint/test/docker-compose.yml` - Docker compose configuration
* `.stoobly/services/entrypoint/test/init` - Initialization script

**Files created for Cypress:**

* `.stoobly/services/entrypoint/test/.Dockerfile.cypress` - Stoobly-maintained base image that pulls in the stock Cypress image (override via `CYPRESS_IMAGE`)
* `.stoobly/services/entrypoint/test/docker-compose.yml` - Docker compose configuration
* `.stoobly/services/entrypoint/test/init` - Initialization script

***

### Docker Initial Setup

#### Q: How do I create a scaffold config for Docker E2E testing?

**A:** Create a declarative config at `.stoobly/scaffold.yml` with your app and service creation steps. Apply it with `stoobly-agent scaffold apply`. Include workflow steps as commented examples for reference. `scaffold apply` itself is runtime-agnostic — for the full command reference and config schema, see:

{% content-ref url="/pages/vNbSv8Y3FUGMz3PL3GyX" %}
[Apply](/faq/scaffold/apply)
{% endcontent-ref %}

**Example:**

```yaml
# .stoobly/scaffold.yml
version: 1
commands:
  - resource: app
    action: create
    options:
      app_name: my-e2e-tests
      runtime: docker
      plugin: [playwright]

  # API runs on localhost:4000, exposed as api.local:80
  # Note: upstream_port is required when using local: true and must differ from port
  # Run your API service on port 4000 (not 80)
  - resource: service
    action: create
    options:
      service_name: api
      hostname: api.local
      port: 80
      scheme: http
      local: true
      upstream_port: 4000

  # UI service (remote, served on app.local:80 for testing)
  - resource: service
    action: create
    options:
      service_name: ui
      hostname: app.local
      port: 80
      scheme: http
      workflow: [test]

  # Example: Start record workflow
  # make -f .stoobly/services/Makefile record
  # make -f .stoobly/services/Makefile intercept/enable

  # Example: Start mock workflow
  # make -f .stoobly/services/Makefile mock
  # make -f .stoobly/services/Makefile intercept/enable

  # Example: Start test workflow
  # make -f .stoobly/services/Makefile test
  # make -f .stoobly/services/Makefile intercept/enable
```

```bash
stoobly-agent scaffold apply .stoobly/scaffold.yml --dry-run
stoobly-agent scaffold apply .stoobly/scaffold.yml
```

#### Q: How do I scaffold an app for Playwright E2E testing with Docker?

**A:** Create an app with the `--plugin playwright` option and `--runtime docker` to set up Playwright-specific configurations.

**Example:**

```bash
# Create app with Playwright
stoobly-agent scaffold app create my-e2e-tests \
  --plugin playwright \
  --runtime docker
```

#### Q: How do I scaffold an app for Cypress E2E testing with Docker?

**A:** Create an app with the `--plugin cypress` option and `--runtime docker` to set up Cypress-specific configurations.

**Example:**

```bash
# Create app with Cypress
stoobly-agent scaffold app create my-cypress-tests \
  --plugin cypress \
  --runtime docker
```

***

### Docker Configuration Files

#### Q: What files should I modify to add my Playwright tests with Docker?

**A:** After scaffolding, you need to modify the entrypoint service docker-compose.yml to run your tests and your Playwright configuration to use the proxy. To set up Stoobly rules, add them to the workflow `init` script. The example below shows how you would override the Stoobly-managed `entrypoint.playwright` service definition—only do this when you need additional customizations.

**Example - Modify docker-compose.yml:**

```yaml
# .stoobly/services/entrypoint/test/docker-compose.yml
services:
  entrypoint.playwright:
    build:
      context: .
      dockerfile: .Dockerfile.playwright
      args:
        PLAYWRIGHT_IMAGE: mcr.microsoft.com/playwright:v1.40.0-jammy
        USER_ID: ${USER_ID}
    working_dir: /home/stoobly/tests
    volumes:
      - ../../..:/home/stoobly/tests    # Mount your test directory
    depends_on:
      entrypoint.init:
        condition: service_completed_successfully
    networks:
      app.ingress: {}
    environment:
      - HTTP_PROXY=http://gateway:80
      - HTTPS_PROXY=http://gateway:80
      - NO_PROXY=localhost,127.0.0.1
    profiles:
      - ${WORKFLOW_NAME}
    command: npx playwright test          # Your test command
```

**Example - Add Stoobly rules in init script:**

```bash
# .stoobly/services/entrypoint/test/init
#!/bin/bash

# Rewrite production URLs to local services
stoobly-agent setting rewrite set \
  --pattern "https://api.production.com/.*" \
  --method GET --method POST \
  --mode test \
  --hostname api.local

# Exclude third-party tracking
stoobly-agent setting filter set \
  --pattern "https://.*analytics.com/.*" \
  --method GET \
  --mode test \
  --action exclude
```

**Example - Create Playwright config:**

```javascript
// playwright.config.ts (in your project root)
import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    proxy: {
      server: 'http://gateway:80',
    },
    ignoreHTTPSErrors: true,
  },
});
```

#### Q: What files should I modify to add my Cypress tests with Docker?

**A:** For Cypress, modify the entrypoint service docker-compose.yml and Cypress configuration to work with Stoobly's proxy. As with Playwright, the example below overrides the managed `entrypoint.cypress` service definition—only override it when you need custom behavior.

**Example - Modify docker-compose.yml:**

```yaml
# .stoobly/services/entrypoint/test/docker-compose.yml
services:
  entrypoint.cypress:
    build:
      context: .
      dockerfile: .Dockerfile.cypress
      args:
        CYPRESS_IMAGE: cypress/included:13.6.0
        USER_ID: ${USER_ID}
    working_dir: /home/stoobly/e2e
    volumes:
      - ../../..:/home/stoobly/e2e        # Mount your test directory
    depends_on:
      entrypoint.init:
        condition: service_completed_successfully
    networks:
      app.ingress: {}
    environment:
      - HTTP_PROXY=http://gateway:80
      - HTTPS_PROXY=http://gateway:80
    profiles:
      - ${WORKFLOW_NAME}
    command: cypress run                   # Your test command
```

**Example - Create Cypress config:**

```javascript
// cypress.config.js (in your project root)
const { defineConfig } = require('cypress');

module.exports = defineConfig({
  e2e: {
    env: {
      HTTP_PROXY: 'http://gateway:80',
      HTTPS_PROXY: 'http://gateway:80',
    },
  },
});
```

#### Q: How do I add custom npm packages for my Docker tests?

**A:** Don't edit the Stoobly-maintained Dockerfiles (files beginning with a dot). Instead, point `PLAYWRIGHT_IMAGE` or `CYPRESS_IMAGE` at a custom image that already includes your dependencies.

```bash
# Example: override Playwright image when running a workflow
PLAYWRIGHT_IMAGE=my-org/playwright-with-helpers:latest \
  make -f .stoobly/services/Makefile test

# For Cypress
CYPRESS_IMAGE=my-org/cypress-with-plugins:latest \
  make -f .stoobly/services/Makefile test
```

Build those images however you like (e.g., start from `mcr.microsoft.com/playwright` or `cypress/included` and add packages), then reference them with the environment variable. Stoobly will use your custom image without touching the managed `.Dockerfile.*` files.

#### Q: How do I pass environment variables to my Docker tests?

**A:** Add environment variables in the docker-compose.yml file under the `environment` section.

**Example:**

```yaml
# .stoobly/services/entrypoint/test/docker-compose.yml
services:
  entrypoint.playwright:
    environment:
      - HTTP_PROXY=http://gateway:80
      - HTTPS_PROXY=http://gateway:80
      - BASE_URL=http://app.local
      - API_URL=http://api.local
      - TEST_USER_EMAIL=test@example.com
      - TEST_USER_PASSWORD=testpass123
      - NODE_ENV=test
```

***

### Running Docker E2E Tests

#### Q: How do I record E2E test traffic with Docker?

**A:** Use the record workflow to capture all HTTP requests made during your E2E tests.

**Example:**

```bash
# Start record workflow
make -f .stoobly/services/Makefile record
make -f .stoobly/services/Makefile intercept/enable

# Tests run automatically in entrypoint container
# All HTTP requests are recorded

# View recorded requests
stoobly-agent request list

# Create scenario from recorded requests
stoobly-agent scenario create "E2E User Flow"

# Stop workflow
make -f .stoobly/services/Makefile record/down
```

#### Q: How do I run E2E tests with mocked responses using Docker?

**A:** Use the mock workflow to run tests against recorded responses without hitting real APIs.

**Example:**

```bash
# Ensure you have recorded responses
stoobly-agent scenario list

# Start mock workflow
make -f .stoobly/services/Makefile mock
make -f .stoobly/services/Makefile intercept/enable

# Tests run automatically in entrypoint container
# Tests run against mocked responses
# No real API calls are made

# Stop workflow
make -f .stoobly/services/Makefile mock/down
```

#### Q: How do I run E2E tests with response validation using Docker?

**A:** Use the test workflow to validate that responses match expected results.

**Example:**

```bash
# Start test workflow
make -f .stoobly/services/Makefile test
make -f .stoobly/services/Makefile intercept/enable

# Tests run automatically in entrypoint container
# Tests run with response validation
# Stoobly compares actual vs expected responses

# View test results
make -f .stoobly/services/Makefile test/logs

# Stop workflow
make -f .stoobly/services/Makefile test/down
```

#### Q: How do I run specific test files or suites with Docker?

**A:** Modify the command in docker-compose.yml to target specific tests.

**Example for Playwright:**

```yaml
# Run specific test file
command: npx playwright test tests/login.spec.ts

# Run tests with specific tag
command: npx playwright test --grep @smoke

# Run tests in headed mode for debugging
command: npx playwright test --headed
```

**Example for Cypress:**

```yaml
# Run specific spec
command: cypress run --spec "cypress/e2e/login.cy.js"

# Run with specific browser
command: cypress run --browser chrome

# Run with video recording
command: cypress run --video
```

***

### Docker Debugging

#### Q: How do I view test output and logs with Docker?

**A:** Use the logs command to see test execution output.

**Example:**

```bash
# View logs while tests are running
make -f .stoobly/services/Makefile test/logs

# View logs for specific service
make -f .stoobly/services/Makefile test/logs options="--service <SERVICE-NAME>"

# View logs for specific namespace
make -f .stoobly/services/Makefile test/logs options="--namespace <NAMESPACE>"
```

#### Q: How do I debug failing Docker tests?

**A:** Enable headed mode and increase logging verbosity in the docker-compose.yml.

**Example:**

```yaml
# .stoobly/services/entrypoint/test/docker-compose.yml
services:
  entrypoint.playwright:
    environment:
      - DEBUG=pw:api                    # Playwright debug logs
      - PWDEBUG=1                       # Playwright debug mode
    command: npx playwright test --headed --debug
```

#### Q: How do I save test artifacts (screenshots, videos) with Docker?

**A:** Mount an artifacts directory to persist test outputs and configure your test framework to save artifacts.

**Example:**

```yaml
# .stoobly/services/entrypoint/test/docker-compose.yml
services:
  entrypoint.playwright:
    volumes:
      - ../../..:/home/stoobly/tests
      - ../../../test-results:/home/stoobly/tests/test-results  # Artifacts
```

```javascript
// playwright.config.ts
export default defineConfig({
  use: {
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },
  outputDir: 'test-results',
});
```

***

### Docker Best Practices

#### Q: Should I record once and mock for all subsequent runs with Docker?

**A:** Yes, this is the recommended approach for fast, reliable E2E tests that don't depend on external APIs.

**Example:**

```bash
# Step 1: Record once (against real APIs)
make -f .stoobly/services/Makefile record
make -f .stoobly/services/Makefile intercept/enable

# Step 2: Create scenario from recordings
stoobly-agent scenario create "User Journey - Login to Checkout"

# Step 3: Snapshot for version control
stoobly-agent scenario snapshot user-journey --decode
git add .stoobly/snapshots/ && git commit -m "Add E2E test snapshots"

# Step 4: All future runs use mocks (fast, no external dependencies)
make -f .stoobly/services/Makefile mock
make -f .stoobly/services/Makefile intercept/enable
```

#### Q: How do I organize E2E tests by feature with Docker?

**A:** Create separate services or custom workflows for different test suites.

**Example:**

```bash
# Create service for auth tests
stoobly-agent scaffold service create auth-tests \
  --workflow test

# Create service for checkout tests
stoobly-agent scaffold service create checkout-tests \
  --workflow test

# Run specific test suite
make -f .stoobly/services/Makefile test STOOBLY_WORKFLOW_SERVICE_OPTIONS="--service auth-tests"
```

***

### Docker CI/CD Integration

#### Q: Which runtime should I use in CI/CD for E2E testing?

**A:** Docker is recommended for CI/CD as it provides consistent, isolated environments for E2E tests. Set the Makefile option `workflow_up_extra_options="--no-publish"` to prevent Docker port conflicts in shared CI hosts.

**Example:**

```bash
#!/bin/bash

# Update .stoobly/services/entrypoint/test/run to run test command e.g. `npm test`

# CI/CD script with Docker runtime
export STOOBLY_HOSTNAME_INSTALL_CONFIRM=y
export STOOBLY_CA_CERTS_INSTALL_CONFIRM=y

# Use Docker runtime
make -f .stoobly/services/.Makefile test workflow_up_extra_options="--no-publish"

# Cleanup
make -f .stoobly/services/.Makefile test/down
```

#### Q: How do I test with Docker runtime in CI/CD?

**A:** Use Makefile commands in your CI/CD pipeline. Include the Makefile option `workflow_up_extra_options="--no-publish"` on test workflow runs to avoid host port binding collisions.

**Example:**

```yaml
# .github/workflows/test.yml
name: Test with Docker

jobs:
  test-docker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Test with Docker
        run: |
          make -f .stoobly/services/.Makefile test workflow_up_extra_options="--no-publish"
          make -f .stoobly/services/.Makefile test/down
```

#### Q: How do I use the Makefile in CI/CD pipelines?

**A:** Set all confirmation environment variables to avoid prompts and run the desired workflow commands. For CI, set the Makefile option `workflow_up_extra_options="--no-publish"` on test workflow runs.

**Example:**

```bash
#!/bin/bash
# CI/CD script example
export STOOBLY_HOSTNAME_INSTALL_CONFIRM=y
export STOOBLY_CA_CERTS_INSTALL_CONFIRM=y
export STOOBLY_APP_DIR=$PWD

# Start test workflow
make -f .stoobly/services/.Makefile test workflow_up_extra_options="--no-publish"

# Run your tests here
# ...

# Clean up
make -f .stoobly/services/.Makefile test/down
```

#### Q: How do I run workflows in Docker containers for CI/CD?

**A:** The Makefile automatically handles Docker-based workflows. Ensure Docker is running and accessible.

**Example:**

```bash
# Verify Docker is running
docker ps

# Start workflow (automatically uses Docker)
make -f .stoobly/services/.Makefile record
```

***

### Docker Advanced Configuration

#### Q: How do I mount test fixtures and data with Docker?

**A:** Add volume mounts to share fixtures between host and container.

**Example:**

```yaml
# .stoobly/services/entrypoint/test/docker-compose.yml
services:
  entrypoint.playwright:
    volumes:
      - ../../..:/home/stoobly/tests           # Project root
      - ../../../test-data:/home/stoobly/data  # Test data
      - ../../../fixtures:/home/stoobly/fixtures # Fixtures
```

***

### Docker Complete Example

#### Q: What's a complete example of setting up Playwright E2E tests with Docker?

**A:** Here's a full example from scaffold to running tests.

**Step 1: Scaffold the app**

```bash
# Create app with Playwright
stoobly-agent scaffold app create my-e2e-app \
  --plugin playwright \
  --proxy-port 8080 \
  --ui-port 4200

# Add frontend service (test workflow only - serves static assets from fixtures)
stoobly-agent scaffold service create frontend \
  --hostname app.local \
  --port 80 \
  --scheme http \
  --workflow test

# Add API service (all workflows created by default)
# Remote upstream where hostname/port/scheme differ
stoobly-agent scaffold service create api \
  --hostname api.local \
  --port 443 \
  --scheme https \
  --upstream-hostname api.production.com
```

**Step 2: Configure entrypoint docker-compose.yml**

```yaml
# .stoobly/services/entrypoint/test/docker-compose.yml
services:
  entrypoint.playwright:
    build:
      context: .
      dockerfile: .Dockerfile.playwright
      args:
        PLAYWRIGHT_IMAGE: mcr.microsoft.com/playwright:v1.40.0-jammy
        USER_ID: ${USER_ID}
    working_dir: /home/stoobly/app
    volumes:
      - ../../..:/home/stoobly/app
    depends_on:
      entrypoint.init:
        condition: service_completed_successfully
    networks:
      app.ingress: {}
    environment:
      - HTTP_PROXY=http://gateway:80
      - HTTPS_PROXY=http://gateway:80
      - BASE_URL=http://app.local
      - API_URL=http://api.local
    profiles:
      - ${WORKFLOW_NAME}
    command: npx playwright test
```

**Step 3: Configure Stoobly rules**

```bash
# .stoobly/services/entrypoint/test/init
#!/bin/bash

# Rewrite API calls
stoobly-agent setting rewrite set \
  --pattern "https://api.production.com/.*" \
  --method GET --method POST --method PUT --method DELETE \
  --mode test \
  --hostname api.local

# Exclude analytics
stoobly-agent setting filter set \
  --pattern "https://.*analytics.com/.*" \
  --method GET --method POST \
  --mode test \
  --action exclude
```

**Step 4: Create Playwright config**

```javascript
// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  use: {
    baseURL: process.env.BASE_URL || 'http://app.local',
    proxy: {
      server: 'http://gateway:80',
    },
    ignoreHTTPSErrors: true,
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },
  outputDir: 'test-results',
});
```

**Step 5: Create test**

```javascript
// tests/login.spec.ts
import { test, expect } from '@playwright/test';

test('user can login', async ({ page }) => {
  await page.goto('/login');
  
  await page.fill('[name="email"]', 'test@example.com');
  await page.fill('[name="password"]', 'password123');
  await page.click('button[type="submit"]');
  
  await expect(page).toHaveURL('/dashboard');
  await expect(page.locator('h1')).toContainText('Welcome');
});
```

**Step 6: Run tests**

```bash
# Run with recording
make -f .stoobly/services/Makefile record
make -f .stoobly/services/Makefile intercept/enable

# Run with mocking
make -f .stoobly/services/Makefile mock
make -f .stoobly/services/Makefile intercept/enable

# Run with validation
make -f .stoobly/services/Makefile test
make -f .stoobly/services/Makefile intercept/enable
```


# JS Client

The Stoobly JavaScript library (`stoobly`) provides convenient access to `stoobly-agent` from end-to-end testing frameworks such Playwright and Cypress. It enables recording, mocking, and testing HTTP requests directly from your test framework.

## Sub-Pages

* [Setup](/faq/scaffold/e2e-testing/js-client/setup) — Installation, requirements, and importing the library
* [npm Scripts](/faq/scaffold/e2e-testing/js-client/npm-scripts) — Wrapping `stoobly-agent` workflow commands in `package.json`
* [Playwright Integration](/faq/scaffold/e2e-testing/js-client/playwright) — Using `playwrightInterceptor()`, `withPage()`, `withContext()`, and recording
* [Cypress Integration](/faq/scaffold/e2e-testing/js-client/cypress) — Using `cypressInterceptor()`, `enable()`, and recording
* [Configuration](/faq/scaffold/e2e-testing/js-client/configuration) — URL patterns, scenarios, sessions, recording options, and interception control
* [Troubleshooting & Examples](/faq/scaffold/e2e-testing/js-client/troubleshooting) — Debugging, complete examples, and quick reference

## Related Documentation

* For a conceptual intro (intercept modes, scenarios, sessions, context), see [Using the JavaScript Client](/getting-started/integrating-the-javascript-client)
* For scaffold integration, see [../README.md](/faq/scaffold/e2e-testing)
* For Docker runtime, see [../docker.md](/faq/scaffold/e2e-testing/docker)
* For local runtime, see [../local.md](/faq/scaffold/e2e-testing/local)


# Setup

### Installation and Setup

#### Q: How do I install the Stoobly JavaScript library?

**A:** Install the library as a dev dependency using npm or yarn.

**Example:**

```bash
# Install with npm
npm install stoobly --save-dev

# Install with yarn
yarn add -D stoobly
```

#### Q: What are the requirements for using the Stoobly JavaScript library?

**A:** The library requires Node.js 18 or higher and works with Playwright and Cypress test frameworks.

**Example:**

```bash
# Check Node version
node --version
# Should output v18.0.0 or higher

# Install with Playwright
npm install stoobly @playwright/test --save-dev

# Install with Cypress
npm install stoobly cypress --save-dev
```

#### Q: How do I import the Stoobly library?

**A:** Import the library using ES modules or CommonJS syntax.

**Example:**

```javascript
// ES modules (recommended)
import Stoobly from 'stoobly';
import { RecordPolicy, RecordOrder, RecordStrategy } from 'stoobly/constants';

// CommonJS
const Stoobly = require('stoobly');
const { RecordPolicy, RecordOrder, RecordStrategy } = require('stoobly/constants');
```

#### Q: How do I create a `Stoobly` instance, and what if my agent isn't on the default port?

**A:** Pass the agent's URL to the `Stoobly` constructor. It defaults to `http://localhost:4200` if omitted.

**Example:**

```javascript
const stoobly = new Stoobly();  // Uses default localhost:4200
// OR
const stoobly = new Stoobly('http://custom-agent:4200');
```

#### Q: Are TypeScript types available?

**A:** Yes, import types from `stoobly/types`:

```typescript
import {
  InterceptorSettings,
  RecordSettings,
  InterceptorUrl,
  Page,      // Playwright page type
  Route,     // Playwright route type
  Request    // Playwright request type
} from 'stoobly/types';
```


# npm Scripts

### Basic Workflow Scripts

#### Q: How do I run stoobly-agent workflows from npm scripts?

**A:** Add `stoobly:<workflow>` and `stoobly:<workflow>:down` scripts to your `package.json` that call the `stoobly-agent` CLI directly. The `stoobly` npm package is a client library, not a CLI wrapper, so scripts call `stoobly-agent` (installed separately — see [Setup](/faq/scaffold/e2e-testing/js-client/setup)), not `npx stoobly`.

**Example:**

```json
{
  "scripts": {
    "stoobly:mock": "stoobly-agent scaffold workflow up mock --detached",
    "stoobly:mock:down": "stoobly-agent scaffold workflow down mock",
    "stoobly:record": "stoobly-agent scaffold workflow up record --detached",
    "stoobly:record:down": "stoobly-agent scaffold workflow down record",
    "stoobly:test": "stoobly-agent scaffold workflow up test --detached",
    "stoobly:test:down": "stoobly-agent scaffold workflow down test",
    "stoobly:develop": "stoobly-agent scaffold workflow up develop --detached",
    "stoobly:develop:down": "stoobly-agent scaffold workflow down develop"
  }
}
```

Run with `npm run stoobly:mock`, then `npm run stoobly:mock:down` when finished.

`mock`, `record`, `test`, and `develop` aren't the only valid workflow names — any workflow created with `scaffold workflow create` (see [Creating Custom Workflows](/faq/scaffold)) works the same way in these scripts.

#### Q: What if my `package.json` isn't at the scaffold app root?

**A:** Scaffold commands default to the current directory for both the app scaffold (`.stoobly/`) and the Stoobly context data. If your npm scripts run from elsewhere — for example a `package.json` nested in a monorepo package — pass `--app-dir-path` pointing at the scaffold app root, and `--context-dir-path` if you want context data (recordings, scenarios) to live somewhere other than that root's default. Both accept relative paths, resolved from the directory `npm run` executes in.

**Example:**

```json
{
  "scripts": {
    "stoobly:mock": "stoobly-agent scaffold workflow up mock --detached --app-dir-path ../.. --context-dir-path .",
    "stoobly:mock:down": "stoobly-agent scaffold workflow down mock --app-dir-path ../.. --context-dir-path ."
  }
}
```

`down` needs the same `--app-dir-path`/`--context-dir-path` values as `up` — they identify which running workflow to stop. See the [Scaffold FAQ](/faq/scaffold/e2e-testing) for more on `--app-dir-path`.

#### Q: Why do my scripts need `--detached`?

**A:** On Docker runtime, `scaffold workflow up` attaches to the entrypoint service's logs by default and doesn't return until you kill it — so a script like `"stoobly-agent scaffold workflow up mock && npx playwright test"` hangs at `up` and never reaches your tests. Pass `--detached` so `up` starts the workflow in the background and returns immediately.

**Example:**

```bash
# Hangs — up never returns, playwright test never runs
stoobly-agent scaffold workflow up mock && npx playwright test

# Returns immediately, tests run next
stoobly-agent scaffold workflow up mock --detached && npx playwright test
```

On local runtime, `up` already starts the agent in the background and returns on its own, so `--detached` is a no-op there. Passing it on every script is safe either way and keeps one script working across both runtimes — see [Docker](/faq/scaffold/e2e-testing/docker) and [Local](/faq/scaffold/e2e-testing/local) for the runtime differences.

***

### Running Tests

#### Q: How do I bring the workflow up, run tests, and tear it down in one command?

**A:** Run `up`, then your test command, capturing its exit code before tearing down — otherwise a failing test run either leaves the workflow running (if you stop at the first failure) or gets its failure masked by `down`'s own exit code (if you naively chain everything with `;`). `scaffold workflow down` is safe to call even when nothing is running (it no-ops), so it's fine to run unconditionally after `up` regardless of whether `up` itself succeeded.

**Example:**

```json
{
  "scripts": {
    "stoobly:mock": "stoobly-agent scaffold workflow up mock --detached",
    "stoobly:mock:down": "stoobly-agent scaffold workflow down mock",
    "test:mock": "npm run stoobly:mock && npx playwright test; RESULT=$?; npm run stoobly:mock:down; exit $RESULT"
  }
}
```

`RESULT=$?` right after `up && test` captures whichever of the two failed (or `0` if both succeeded), `down` always runs next, and `exit $RESULT` makes sure a test failure still fails the npm script — important for CI to detect it.

`scaffold workflow up` returns control to the shell right away (with `--detached`, always, on both runtimes) rather than staying attached, so teardown needs this explicit `down` step regardless of how your test command itself is structured. That's true even if your test command is a wrapper that also starts and stops your app's dev server — common approaches include `start-server-and-test`, Playwright's built-in [`webServer`](https://playwright.dev/docs/test-webserver) config, or just running the dev server in a separate terminal. Whichever you use, it only manages your app's dev server, not the Stoobly workflow — `stoobly:mock`/`stoobly:mock:down` still wrap it as shown above.

If that dev server itself makes HTTPS calls through the Stoobly proxy, it may need to be told to trust Stoobly's certificate separately from your browser — see the [CA Cert FAQ](/faq/ca-cert).

#### Q: How do I pick the intercept mode from an npm script?

**A:** Set `STOOBLY_INTERCEPT_MODE` inline before your test command. See [Configuration](/faq/scaffold/e2e-testing/js-client/configuration) for how the JS client reads this variable.

**Example:**

```json
{
  "scripts": {
    "stoobly:record": "stoobly-agent scaffold workflow up record --detached",
    "stoobly:record:down": "stoobly-agent scaffold workflow down record",
    "test:record": "npm run stoobly:record && cross-env STOOBLY_INTERCEPT_MODE=record npx playwright test; RESULT=$?; npm run stoobly:record:down; exit $RESULT"
  }
}
```

`cross-env` sets the variable in a way that works on both POSIX shells (macOS/Linux) and Windows; without it, `STOOBLY_INTERCEPT_MODE=record npx playwright test` only works on POSIX shells.

***

### Diagnostics

#### Q: How do I check what's running or view logs from npm?

**A:** Add scripts for `scaffold workflow show`, `scaffold workflow logs`, and `scaffold request logs list`. There are two distinct log commands and both are worth having: `workflow logs` shows raw workflow process output (startup errors, config issues), while `request logs list` shows what requests were intercepted and whether they were mocked or passed through — the first thing to check when debugging mock behavior. `show` works with no arguments (lists all running workflows); the two log commands require a workflow name, so pass it through with `npm run <script> --`.

**Example:**

```json
{
  "scripts": {
    "stoobly:show": "stoobly-agent scaffold workflow show",
    "stoobly:workflow-logs": "stoobly-agent scaffold workflow logs",
    "stoobly:request-logs": "stoobly-agent scaffold request logs list"
  }
}
```

```bash
npm run stoobly:show
npm run stoobly:workflow-logs -- mock --follow
npm run stoobly:request-logs -- mock --follow
```

`--follow` streams either log in real time and works the same way on both.

***

### CI/CD

#### Q: How do I make these scripts work in CI?

**A:** `scaffold workflow up` can prompt to install the CA certificate (first run of the record workflow) and, on Docker runtime, to install hostnames — both hang a non-interactive CI job. Pass `--ca-certs-install-confirm y` and `--hostname-install-confirm y` to answer them automatically, and install the CA cert as a separate setup step.

**Example:**

```json
{
  "scripts": {
    "stoobly:test": "stoobly-agent scaffold workflow up test --detached --ca-certs-install-confirm y --hostname-install-confirm y",
    "stoobly:test:down": "stoobly-agent scaffold workflow down test"
  }
}
```

```yaml
# .github/workflows/test.yml
name: E2E Tests

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v4
      - name: Install stoobly-agent
        run: pipx install stoobly-agent
      - name: Install Stoobly CA cert
        run: sudo stoobly-agent ca-cert install
      - name: Install dependencies
        run: npm ci
      - name: Run E2E tests
        run: npm run test:mock
```

See [Local](/faq/scaffold/e2e-testing/local) for more on running the local runtime in CI.


# Playwright

### Playwright Integration

#### Q: How do I integrate Stoobly with Playwright tests?

**A:** Prefer initializing Stoobly in a custom Playwright fixture so interception starts before any other fixtures that might trigger network calls. In that fixture, set `withContext()` or `withPage()`, call `enable()` (pass `{ mode: InterceptMode.record }` when recording), and set `withTestTitle()` using `testInfo`.

Instead of managing a `scenarioKey`, derive a scenario name from the hierarchical test title path — this is more intuitive and one less thing to configure. Compute it from `testInfo.titlePath` and pass it in the interceptor options:

`const scenarioName = testInfo.titlePath.join(' > '); // pass as { scenarioName }`

**Example:**

```javascript
import { test as base, expect } from '@playwright/test';
import Stoobly from 'stoobly';

// Create a test fixture that initializes Stoobly early
const test = base.extend({
  stooblyInterceptor: [
    async ({ context, page }, use, testInfo) => {
      const stoobly = new Stoobly();
      const scenarioName = testInfo.titlePath.join(' > ');
      const interceptor = stoobly.playwrightInterceptor({
        urls: [new RegExp('https://api.example.com/.*')],
        scenarioName,
      });

      // Choose one based on scope:
      await interceptor.withContext(context).enable(); // recommended for multi-page tests
      // await interceptor.withPage(page).enable();    // for single-page tests
      interceptor.withTestTitle(testInfo.title);

      await use(undefined);
    },
    { auto: true }, // ensure it runs automatically before the test starts
  ],
});

test.describe('My Tests', () => {
  test('can fetch data', async ({ page }) => {
    await page.goto('https://example.com');
    // Your test code here
  });
});
```

#### Q: Why do I need to call `withPage()` and `withTestTitle()` in Playwright?

**A:** Playwright doesn't provide a global API to auto-detect the current page or test title, so you must explicitly set them in a setup point. Use a custom fixture (recommended) so interception is active before other fixtures run, or set them in `beforeEach` if you cannot use a fixture.

**Example:**

```javascript
// Fixture approach (recommended)
const test = base.extend({
  stooblyInterceptor: [
    async ({ context, page }, use, testInfo) => {
      const stoobly = new Stoobly();
      const interceptor = stoobly.playwrightInterceptor({
        urls: [/https:\/\/api\.example\.com\/.*/],
        scenarioName: testInfo.titlePath.join(' > '),
      });
      await interceptor.withContext(context).enable();
      interceptor.withTestTitle(testInfo.title);
      await use(undefined);
    },
    { auto: true },
  ],
});

// Fallback: beforeEach (if fixtures not possible)
// test.beforeEach(async ({ page }, testInfo) => {
//   await interceptor.withPage(page).enable();
//   interceptor.withTestTitle(testInfo.title);
// });
```

#### Q: When should I use `withContext()` instead of `withPage()`?

**A:** Use `withContext()` when you need to intercept requests from all pages in a browser context, including new pages created during tests. Use `withPage()` when you only want to intercept requests from a specific page.

**Key differences:**

* **`withPage()`** - Intercepts requests only from the specified page. New pages created in the same context will NOT be intercepted.
* **`withContext()`** - Intercepts requests from all pages in the browser context, including pages created with `context.newPage()`, browser extensions, and service workers.
* **Both together** - You can use both `withContext()` and `withPage()` to ensure all pages are intercepted.

**Example:**

```javascript
import { test } from '@playwright/test';
import Stoobly from 'stoobly';

const stoobly = new Stoobly();
const interceptor = stoobly.playwrightInterceptor({
  urls: [new RegExp('https://api.example.com/.*')],
});

// Scenario 1: Single page interception
test.describe('Page-only interception', () => {
  // Prefer setting this in a fixture; shown here only if fixtures aren't used
  test.beforeEach(async ({ page }, testInfo) => {
    await interceptor.withPage(page).enable();
    interceptor.withTestTitle(testInfo.title);
    interceptor.withScenarioName(testInfo.titlePath.join(' > '));
  });

  test('intercepts only the fixture page', async ({ context, page }) => {
    await page.goto('https://example.com'); // ✓ Intercepted

    // Create a new page
    const page2 = await context.newPage();
    await page2.goto('https://example.com'); // ✗ NOT intercepted
    await page2.close();
  });
});

// Scenario 2: Context-wide interception (recommended for multi-page tests)
test.describe('Context-wide interception', () => {
  // Prefer setting this in a fixture; shown here only if fixtures aren't used
  test.beforeEach(async ({ context }, testInfo) => {
    await interceptor.withContext(context).enable();
    interceptor.withTestTitle(testInfo.title);
    interceptor.withScenarioName(testInfo.titlePath.join(' > '));
  });

  test('intercepts all pages in context', async ({ context }) => {
    const page1 = await context.newPage();
    await page1.goto('https://example.com'); // ✓ Intercepted

    const page2 = await context.newPage();
    await page2.goto('https://example.com'); // ✓ Intercepted

    await page1.close();
    await page2.close();
  });
});

// Scenario 3: Both page and context interception
test.describe('Dual interception', () => {
  // Prefer setting this in a fixture; shown here only if fixtures aren't used
  test.beforeEach(async ({ context, page }, testInfo) => {
    await interceptor.withContext(context).withPage(page).enable();
    interceptor.withTestTitle(testInfo.title);
  });

  test('intercepts fixture page and new pages', async ({ context, page }) => {
    await page.goto('https://example.com'); // ✓ Intercepted (via both)

    const page2 = await context.newPage();
    await page2.goto('https://example.com'); // ✓ Intercepted (via context)
    await page2.close();
  });
});
```

**Use `withContext()` when:**

1. Your tests create multiple pages (popups, new tabs)
2. You're testing browser extensions that make background requests
3. You're testing service workers
4. You want consistent interception across all pages without calling `withPage()` for each

**Use `withPage()` when:**

1. You only work with the test fixture page
2. You want fine-grained control over which pages are intercepted
3. You're following the typical Playwright test pattern with a single page

#### Q: How do I intercept `context.request` (API tests) in Playwright?

**A:** `withPage()` and `withContext()` use Playwright's `page.route()` / `context.route()` internally, which only intercepts requests made by **browser pages** — not requests made via `context.request` (Playwright's `APIRequestContext`). For API tests that use `context.request`, you must also call `context.setExtraHTTPHeaders()` with the interceptor's headers after `enable()`.

This works because `context.request` calls still travel through any proxy configured in `playwright.config.ts`. Adding the Stoobly headers via `setExtraHTTPHeaders` ensures those calls carry the correct `X-Stoobly-Proxy-Mode`, `X-Stoobly-Scenario-Key`, and session headers to the proxy.

**Example:**

```javascript
import { test } from '@playwright/test';
import Stoobly from 'stoobly';
import { InterceptMode, RecordPolicy, RecordOrder, RecordStrategy } from 'stoobly/constants';

const isRecording = process.env.STOOBLY_RECORD === 'true';

const stoobly = new Stoobly();
const interceptor = stoobly.playwrightInterceptor({
  urls: [new RegExp('http://localhost:3000/api/.*')],
  record: {
    policy: RecordPolicy.All,
    order: RecordOrder.Overwrite,
    strategy: RecordStrategy.Full,
  },
});

test.describe('API Tests', () => {
  test.beforeEach(async ({ context }, testInfo) => {
    interceptor.withContext(context);
    interceptor.withTestTitle(testInfo.title);
    interceptor.withScenarioKey('<SCENARIO-KEY>');

    if (isRecording) {
      await interceptor.enable({ mode: InterceptMode.record });
    } else {
      await interceptor.enable({ mode: InterceptMode.mock });
    }

    // Required for context.request: context.route() does NOT intercept APIRequestContext.
    // Copy interceptor headers onto the context so context.request calls carry them to the proxy.
    await context.setExtraHTTPHeaders((interceptor as any).headers);
  });

  test('fetches data via context.request', async ({ context }) => {
    const resp = await context.request.get('/api/users');
    // Request reaches proxy with Stoobly headers → recorded or mocked correctly
  });
});
```

**Key points:**

* `withContext(context)` sets up `context.route()` for browser page requests only
* `context.setExtraHTTPHeaders((interceptor as any).headers)` must be called **after** `enable()` so the headers reflect the current session ID, scenario key, and proxy mode
* `headers` is a `protected` field on the interceptor class; `(interceptor as any).headers` accesses it at runtime

***

#### Q: How do I record requests in Playwright tests?

**A:** Set intercept **`mode`** to record—either in the interceptor constructor (`mode: InterceptMode.record`) or when calling `enable({ mode: InterceptMode.record })`.

**Example:**

```javascript
import { test as base } from '@playwright/test';
import Stoobly from 'stoobly';
import { InterceptMode, RecordPolicy, RecordOrder, RecordStrategy } from 'stoobly/constants';

// Fixture-based recording setup
const test = base.extend({
  stooblyInterceptor: [
    async ({ context }, use, testInfo) => {
      const stoobly = new Stoobly();
      const interceptor = stoobly.playwrightInterceptor({
        urls: [new RegExp('https://api.example.com/.*')],
        scenarioName: testInfo.titlePath.join(' > '),
        mode: InterceptMode.record,
        record: {
          policy: RecordPolicy.All,
          order: RecordOrder.Overwrite,
          strategy: RecordStrategy.Full,
        }
      });
      await interceptor.withContext(context).enable();
      interceptor.withTestTitle(testInfo.title);
      await use(undefined);
    },
    { auto: true },
  ],
});

test.describe('Record Requests', () => {
  test('records API calls', async ({ page }) => {
    await page.goto('https://example.com');
    // All API requests matching urls will be recorded
  });
});
```


# Cypress

### Cypress Integration

#### Q: How do I integrate Stoobly with Cypress tests?

**A:** Create a Stoobly instance and Cypress interceptor, then call `enable()` in your `beforeEach` hook.

**Example:**

```javascript
import Stoobly from 'stoobly';
import { RecordPolicy, RecordOrder, RecordStrategy } from 'stoobly/constants';

const stoobly = new Stoobly();
const interceptor = stoobly.cypressInterceptor({
  urls: [new RegExp('https://api.example.com/.*')],
});

describe('My Tests', () => {
  // Use function() form to access Mocha context
  beforeEach(function () {
    // Derive hierarchical scenario name from the test path
    const scenarioName = this.test.titlePath().join(' > ');
    interceptor.withScenarioName(scenarioName);

    // Enable interceptor in beforeEach
    interceptor.enable();
  });

  it('can fetch data', () => {
    cy.visit('https://example.com');
    // Your test code here
  });
});
```

#### Q: Why must I call `enable()` in `beforeEach` for Cypress?

**A:** Cypress automatically clears all intercepts before every test, so you must reapply the Stoobly interceptor in `beforeEach`.

**Example:**

```javascript
describe('API Tests', () => {
  beforeEach(function () {
    // Required: Reapply interceptor for each test
    // Cypress clears cy.intercept between tests
    const scenarioName = this.test.titlePath().join(' > ');
    interceptor.withScenarioName(scenarioName);
    interceptor.enable();
  });

  it('test 1', () => {
    // Interceptor is active
  });

  it('test 2', () => {
    // Interceptor must be reapplied (done in beforeEach)
  });
});
```

#### Q: How do I record requests in Cypress tests?

**A:** Set **`mode: InterceptMode.record`** in the interceptor settings (constructor options) and call `enable()` as usual, **or** call `enable({ mode: InterceptMode.record })` in `beforeEach`.

**Example:**

```javascript
import Stoobly from 'stoobly';
import { InterceptMode, RecordPolicy, RecordOrder, RecordStrategy } from 'stoobly/constants';

const stoobly = new Stoobly();
const interceptor = stoobly.cypressInterceptor({
  urls: ['https://api.example.com/users'],
  mode: InterceptMode.record,
  record: {
    policy: RecordPolicy.All,
    order: RecordOrder.Overwrite,
    strategy: RecordStrategy.Full,
  }
});

describe('Record Requests', () => {
  beforeEach(function () {
    const scenarioName = this.test.titlePath().join(' > ');
    interceptor.withScenarioName(scenarioName);
    interceptor.enable();
  });

  it('records API calls', () => {
    cy.visit('https://example.com');
    // All API requests matching urls will be recorded
  });
});
```

#### Q: What's the warning about synchronous requests in Cypress?

**A:** Synchronous XMLHttpRequest calls will cause Cypress to hang. Avoid using synchronous requests when Stoobly interceptor is active.

**Example:**

```javascript
// BAD: Synchronous request (will hang Cypress)
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', false); // false = synchronous
xhr.send();

// GOOD: Asynchronous request (works correctly)
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true); // true = asynchronous
xhr.send();

// BETTER: Use fetch or Cypress commands
cy.request('GET', 'https://api.example.com/data');
```


# Configuration

### Configuring URL Patterns

#### Q: How do I specify which URLs to intercept?

**A:** Use the `urls` array with strings or regular expressions to filter which requests Stoobly intercepts.

**Example:**

```javascript
const stoobly = new Stoobly();

// Exact URL match
const interceptor1 = stoobly.playwrightInterceptor({
  urls: ['https://api.example.com/users'],
});

// Regex pattern (match all API endpoints)
const interceptor2 = stoobly.playwrightInterceptor({
  urls: [new RegExp('https://api.example.com/.*')],
});

// Multiple URLs
const interceptor3 = stoobly.playwrightInterceptor({
  urls: [
    'https://api.example.com/users',
    'https://api.example.com/products',
    new RegExp('https://cdn.example.com/.*'),
  ],
});
```

#### Q: How do I configure per-URL options like match rules or fixture paths?

**A:** Pass `InterceptorUrl` objects in the `urls` array to attach per-URL configuration such as match rules, rewrite rules, a public directory path, or a response fixtures path.

**InterceptorUrl shape:**

```typescript
interface InterceptorUrl {
  pattern: RegExp | string;       // required: the URL to match
  matchRules?: MatchRule[];        // optional: which request components to match on
  rewriteRules?: RewriteRule[];    // optional: rules to rewrite request parameters or URL parts
  publicDirectoryPath?: string;    // optional: path to a public directory for static responses
  responseFixturesPath?: string;   // optional: path to response fixture files
}
```

**Example:**

```javascript
import Stoobly from 'stoobly';
import { InterceptMode, RequestParameter } from 'stoobly/constants';

const stoobly = new Stoobly();
const interceptor = stoobly.playwrightInterceptor({
  urls: [
    // Simple string — no per-URL config needed
    'https://api.example.com/users',

    // Simple RegExp — matches all API endpoints
    new RegExp('https://api.example.com/products/.*'),

    // InterceptorUrl object — match only on headers during replay
    {
      pattern: new RegExp('https://api.example.com/orders/.*'),
      matchRules: [
        { modes: [InterceptMode.replay], components: RequestParameter.Header },
      ],
    },

    // InterceptorUrl object — serve responses from local fixtures
    {
      pattern: 'https://api.example.com/catalog',
      responseFixturesPath: './fixtures/catalog',
    },
  ],
});
```

**Use `InterceptorUrl` when:**

1. You need different match rules for specific endpoints
2. You want to serve static fixture files for certain URLs
3. You need rewrite rules applied to a subset of intercepted URLs

***

#### Q: How do I change the intercepted URLs dynamically?

**A:** Pass a new `urls` array to `enable()` to update which URLs are intercepted.

**Example:**

```javascript
const interceptor = stoobly.playwrightInterceptor({
  urls: [new RegExp('https://api.example.com/.*')],
});

test.beforeEach(async ({ page }) => {
  await interceptor.withPage(page).enable();
});

test('changes URLs dynamically', async ({ page }) => {
  // Initially intercepts api.example.com
  await page.goto('https://example.com');

  // Change to intercept different URLs
  await interceptor.enable({
    urls: [new RegExp('https://cdn.example.com/.*')]
  });

  // Now intercepts cdn.example.com instead
  await page.goto('https://example.com');
});
```

***

### Request Matching

#### Q: What determines whether a request matches a recording during mocking?

**A:** Stoobly matches requests against recordings using these components, in order (case-sensitive):

1. **HTTP Method** (required) — GET, POST, PUT, DELETE, etc.
2. **Path** (required) — e.g., `/users`
3. **Query Parameters** — Sorted alphabetically before comparison
4. **Headers** — Sorted alphabetically before comparison
5. **Body** — Strict matching if provided
6. **Body Parameters** — Parsed from JSON or form-urlencoded, sorted alphabetically

If a `scenarioKey` or `scenarioName` is set, only requests within that scenario are considered; otherwise any matching recorded request is used. Multiple matches within a scenario return responses in recording order. Use per-URL `matchRules` (see above) to relax which components are compared.

***

### Scenarios and Sessions

#### Q: How do I specify a scenario for my tests?

**A:** Prefer `scenarioName` in the interceptor options to associate requests with a scenario. This is more intuitive and avoids managing keys. You can also derive it from your test framework (e.g., Playwright `testInfo.titlePath.join(' > ')`).

**Example:**

```javascript
// Using scenario name (recommended)
const interceptor1 = stoobly.playwrightInterceptor({
  scenarioName: 'my-test-scenario',
  urls: [new RegExp('https://api.example.com/.*')],
});

// Deriving scenario name from environment or test metadata
const scenarioFromEnv = process.env.STOOBLY_SCENARIO_NAME || 'default-scenario';
const interceptor2 = stoobly.playwrightInterceptor({
  scenarioName: scenarioFromEnv,
  urls: [new RegExp('https://api.example.com/.*')],
});
```

#### Q: How do I change the scenario dynamically?

**A:** Use `withScenarioName()` to update the scenario.

**Example:**

```javascript
const interceptor = stoobly.playwrightInterceptor({
  urls: [new RegExp('https://api.example.com/.*')],
});

test('switches scenarios', async ({ page }) => {
  // Use scenario A
  interceptor.withScenarioName('scenario-a');
  await interceptor.withPage(page).enable();
  await page.goto('https://example.com');

  // Switch to scenario B
  interceptor.withScenarioName('scenario-b');
  await page.goto('https://example.com/other');
});
```

#### Q: What is a session ID and how do I use it?

**A:** A session ID groups requests together within a scenario. It defaults to the current timestamp but can be customized for test reproducibility.

**Example:**

```javascript
// Default session ID (auto-generated timestamp)
const interceptor1 = stoobly.playwrightInterceptor({
  urls: [new RegExp('https://api.example.com/.*')],
});

// Custom session ID
const interceptor2 = stoobly.playwrightInterceptor({
  sessionId: 'test-session-123',
  urls: [new RegExp('https://api.example.com/.*')],
});

// Change session ID dynamically
test('changes session', async ({ page }) => {
  interceptor.withSessionId('session-1');
  await interceptor.withPage(page).enable();
  await page.goto('https://example.com');

  interceptor.withSessionId('session-2');
  await page.goto('https://example.com/other');
});
```

***

### Recording Configuration

#### Q: What record policies are available?

**A:** Stoobly supports three record policies: `All` (record everything), `Found` (record only if request exists), and `NotFound` (record only new requests).

**Example:**

```javascript
import { RecordPolicy } from 'stoobly/constants';

// Record all requests (default)
const interceptor1 = stoobly.playwrightInterceptor({
  urls: [new RegExp('https://api.example.com/.*')],
  record: { policy: RecordPolicy.All },
});

// Record only if request already exists in scenario
const interceptor2 = stoobly.playwrightInterceptor({
  urls: [new RegExp('https://api.example.com/.*')],
  record: { policy: RecordPolicy.Found },
});

// Record only new requests (not already in scenario)
const interceptor3 = stoobly.playwrightInterceptor({
  urls: [new RegExp('https://api.example.com/.*')],
  record: { policy: RecordPolicy.NotFound },
});
```

#### Q: What's the difference between record orders?

**A:** `Overwrite` replaces existing requests with the same signature, while `Append` always creates new request records.

**Example:**

```javascript
import { RecordOrder } from 'stoobly/constants';

// Overwrite existing requests (useful for updating mocks)
const interceptor1 = stoobly.playwrightInterceptor({
  urls: [new RegExp('https://api.example.com/.*')],
  record: { order: RecordOrder.Overwrite },
});

// Append new requests (useful for collecting multiple responses)
const interceptor2 = stoobly.playwrightInterceptor({
  urls: [new RegExp('https://api.example.com/.*')],
  record: { order: RecordOrder.Append },
});
```

**Note:** `Overwrite` is sent only once **per URL pattern** per session. Subsequent requests to the same URL pattern use `Append` behavior. Each URL pattern is tracked independently, so multiple patterns can each receive one overwrite.

#### Q: What record strategies are available?

**A:** Stoobly supports `Full` (record complete request/response) and `Minimal` (record only essential data).

**Example:**

```javascript
import { RecordStrategy } from 'stoobly/constants';

// Full recording (complete request and response data)
const interceptor1 = stoobly.playwrightInterceptor({
  urls: [new RegExp('https://api.example.com/.*')],
  record: { strategy: RecordStrategy.Full },
});

// Minimal recording (essential data only)
const interceptor2 = stoobly.playwrightInterceptor({
  urls: [new RegExp('https://api.example.com/.*')],
  record: { strategy: RecordStrategy.Minimal },
});
```

#### Q: How do I change record settings dynamically?

**A:** Use `withRecordPolicy()`, `withRecordOrder()`, and `withRecordStrategy()` methods.

**Example:**

```javascript
import { InterceptMode, RecordPolicy, RecordOrder, RecordStrategy } from 'stoobly/constants';

const interceptor = stoobly.playwrightInterceptor({
  urls: [new RegExp('https://api.example.com/.*')],
});

test('changes record settings', async ({ page }) => {
  // Set record options
  interceptor.withRecordPolicy(RecordPolicy.All);
  interceptor.withRecordOrder(RecordOrder.Overwrite);
  interceptor.withRecordStrategy(RecordStrategy.Full);

  await interceptor.withPage(page).enable({ mode: InterceptMode.record });
  await page.goto('https://example.com');

  // Change to minimal strategy
  interceptor.withRecordStrategy(RecordStrategy.Minimal);
  await page.goto('https://example.com/other');
});
```

***

### Controlling Interception

#### Q: How do I manage the intercept mode (mock, record, replay) for tests?

**A:** The simplest, CI-friendly way is to set the `STOOBLY_INTERCEPT_MODE` environment variable before running your tests. This avoids hardcoding modes in code and keeps behavior consistent across local and CI.

Try:

1. Set an environment variable for the whole test run:
   * macOS/Linux:

     ```bash
     export STOOBLY_INTERCEPT_MODE=mock
     npx playwright test
     ```
   * One-off run:

     ```bash
     STOOBLY_INTERCEPT_MODE=record npx playwright test
     ```
2. Set per-interceptor in code if needed for a specific suite (derive from the environment variable):

   ```javascript
   import Stoobly from 'stoobly';
   import { InterceptMode } from 'stoobly/constants';

   // Derive mode from environment with a safe default
   const envMode = (process.env.STOOBLY_INTERCEPT_MODE || 'mock').toLowerCase();
   const mode =
     envMode === 'record' ? InterceptMode.record :
     envMode === 'replay' ? InterceptMode.replay :
     InterceptMode.mock; // default

   const stoobly = new Stoobly();
   const interceptor = stoobly.playwrightInterceptor({
     urls: [new RegExp('https://api.example.com/.*')],
     mode,
   });
   ```

More details: Intercept FAQ (`https://docs.stoobly.com/faq/intercept`)

#### Q: How do I stop recording requests?

**A:** Call `enable({ mode: InterceptMode.mock })` (or another non-record mode) to stop recording while keeping interception active. `apply`/`clear` remain as deprecated aliases for `enable`/`disable`.

**Example:**

```javascript
import { InterceptMode } from 'stoobly/constants';

test('stops recording', async ({ page }) => {
  // Start recording
  await interceptor.withPage(page).enable({ mode: InterceptMode.record });
  await page.goto('https://example.com'); // Recorded

  // Stop recording (still intercepted — typically mock)
  await interceptor.enable({ mode: InterceptMode.mock });
  await page.goto('https://example.com/other'); // Mock / your non-record mode
});
```

#### Q: How do I completely remove the interceptor?

**A:** Use `disable()` to remove all interception and reset session state for the next `enable()`.

**Example:**

```javascript
test('removes interceptor', async ({ page }) => {
  // Enable interceptor
  await interceptor.withPage(page).enable();
  await page.goto('https://example.com'); // Intercepted

  // Remove interceptor
  await interceptor.disable();
  await page.goto('https://example.com/other'); // Not intercepted
});
```

#### Q: What's the difference between `disable()` and switching modes with `enable()`?

**A:** `disable()` tears down interception (routes / patches) and resets the session id that `enable()` will assign next. To **keep** intercepting but stop recording, call `enable({ mode: InterceptMode.mock })` instead of `disable()`.

**Example:**

```javascript
import { InterceptMode } from 'stoobly/constants';

// Switch mode — keeps interception active
test('switch from record to mock', async ({ page }) => {
  await interceptor.withPage(page).enable({ mode: InterceptMode.record });
  await page.goto('https://example.com'); // Recorded

  await interceptor.enable({ mode: InterceptMode.mock });
  await page.goto('https://example.com'); // Mock only
});

// disable() — removes everything
test('disable example', async ({ page }) => {
  await interceptor.withPage(page).enable();
  await page.goto('https://example.com'); // Intercepted

  await interceptor.disable();
  await page.goto('https://example.com'); // No interception
});
```

***

### Advanced Configuration

#### Q: How do I set a custom Stoobly UI URL?

**A:** Pass the UI URL to the Stoobly constructor if your agent is running on a different port or host.

**Example:**

```javascript
// Default (http://localhost:4200)
const stoobly1 = new Stoobly();

// Custom URL
const stoobly2 = new Stoobly('http://localhost:8080');

// Remote agent
const stoobly3 = new Stoobly('https://stoobly-agent.company.com');
```

#### Q: How do I use test titles for request grouping?

**A:** Set test titles using `withTestTitle()` to group requests by test name in the Stoobly UI.

**Example:**

```javascript
// Playwright (manual test title)
test.beforeEach(async ({ page }, testInfo) => {
  await interceptor.withPage(page).enable();
  interceptor.withTestTitle(testInfo.title);
});

// Cypress (auto-detected test title)
beforeEach(() => {
  interceptor.enable();
  // Test title is automatically detected
});

// Clear test title
interceptor.withTestTitle(undefined);
```

#### Q: Can I use the interceptor without a test framework?

**A:** Yes, use the generic `interceptor()` method for vanilla JavaScript applications.

**Example:**

```javascript
import Stoobly from 'stoobly';

const stoobly = new Stoobly();
const interceptor = stoobly.interceptor({
  scenarioName: '<SCENARIO-NAME>',
  urls: [new RegExp('https://api.example.com/.*')],
});

// Enable interception
const sessionId = interceptor.enable();
console.log('Session ID:', sessionId);

// Make requests (fetch/XMLHttpRequest will be intercepted)
fetch('https://api.example.com/users');

// Stop interception
interceptor.disable();
```

#### Q: How do I read or update the Stoobly agent's configuration from my tests?

**A:** Use the `config` property on the `Stoobly` instance to dump the agent's full configuration, get a summary, or set the active scenario.

**Example:**

```javascript
const stoobly = new Stoobly();

// Get full configuration
const config = await stoobly.config.dump();

// Get configuration summary
const summary = await stoobly.config.summary();

// Set active scenario
await stoobly.config.scenario.set('<SCENARIO-KEY>');
```

***

### Constants Reference

#### Q: What other constants does `stoobly/constants` export besides RecordPolicy, RecordOrder, RecordStrategy, and InterceptMode?

**A:** `stoobly/constants` also exports enums for mocking, replaying, testing, and request filtering/matching:

```typescript
enum MockPolicy {
  All = 'all'     // Mock all requests (return 404 if not found)
  Found = 'found' // Mock only requests with recordings (pass-through others)
}

enum ReplayPolicy {
  All = 'all'  // Replay all requests
}

enum TestPolicy {
  All = 'all'     // Test all requests
  Found = 'found' // Test only requests with recordings
}

enum TestStrategy {
  Diff = 'diff'     // Exact difference comparison
  Fuzzy = 'fuzzy'   // Approximate comparison
  Custom = 'custom' // Custom comparison logic
}

enum FilterAction {
  Exclude = 'exclude' // Block matching URLs
  Include = 'include' // Allow matching URLs
}

enum RequestParameter {
  Header = 'Header'          // HTTP headers
  BodyParam = 'Body Param'   // Request body parameters
  QueryParam = 'Query Param' // URL query parameters
}
```

`MockPolicy` is set via `mock: { policy }` in `InterceptorSettings` (or `withMockPolicy()`). `RequestParameter` is used in per-URL `matchRules`/`rewriteRules` (see [Configuring URL Patterns](#configuring-url-patterns) above) to specify which request components to match on or rewrite.


# Troubleshooting & Examples

### Troubleshooting

#### Q: Why are my Playwright requests missing the scenario key?

**A:** Ensure you call `withPage(page)` (or `withContext(context)`) before `enable()`. The `withPage()` call does not reset headers; you can set `withScenarioKey()` or `withScenarioName()` either before or after `withPage()`, as long as it is in effect when `enable()` runs.

**Example:**

```javascript
// Recommended order in beforeEach (Playwright)
test.beforeEach(async ({ page }, testInfo) => {
  interceptor.withScenarioKey('<SCENARIO-KEY>');      // can be before or after withPage
  interceptor.withTestTitle(testInfo.title);
  await interceptor.withPage(page).enable();           // enable after withPage
});
```

***

#### Q: Why aren't my requests being intercepted?

**A:** Verify the URL patterns match your requests, the interceptor is applied in `beforeEach`, and stoobly-agent is running.

**Example:**

```javascript
// Check URL pattern
const interceptor = stoobly.playwrightInterceptor({
  urls: [new RegExp('https://api.example.com/.*')], // Make sure pattern matches
  scenarioKey: '<SCENARIO-KEY>',
});

test.beforeEach(async ({ page }, testInfo) => {
  // Ensure interceptor is applied
  await interceptor.withPage(page).enable();
  interceptor.withTestTitle(testInfo.title);
});

// Verify stoobly-agent is running
// stoobly-agent run --headless
```

#### Q: How do I debug interceptor issues?

**A:** Check the browser's network tab for Stoobly headers and verify the agent is receiving requests.

**Example:**

```javascript
// Add logging to verify interceptor is working
test('debug interceptor', async ({ page }) => {
  const sessionId = await interceptor.withPage(page).enable();
  console.log('Session ID:', sessionId);

  // Check request headers in browser DevTools
  await page.goto('https://example.com');
});
```

**HTTP Headers Injected**

The library injects these custom headers into matching HTTP requests — check the Network tab for them when debugging:

| Header                             | Description                                                                    |
| ---------------------------------- | ------------------------------------------------------------------------------ |
| `X-Stoobly-Proxy-Mode`             | Active intercept mode (mock/record/replay/test)                                |
| `X-Stoobly-Record-Order`           | Recording order (append/overwrite)                                             |
| `X-Stoobly-Record-Policy`          | Recording policy (all/found/not\_found)                                        |
| `X-Stoobly-Record-Strategy`        | Recording strategy (full/minimal)                                              |
| `X-Stoobly-Scenario-Key`           | Base64-encoded scenario identifier                                             |
| `X-Stoobly-Scenario-Name`          | Human-readable scenario name                                                   |
| `X-Stoobly-Session-Id`             | Current session identifier                                                     |
| `X-Stoobly-Test-Title`             | Current test name (auto-detected or manual)                                    |
| `X-Stoobly-Overwrite-Id`           | Present when using `RecordOrder.Overwrite`, first request per URL pattern only |
| `X-Stoobly-Match-Rules`            | Present when using per-URL `matchRules`                                        |
| `X-Stoobly-Rewrite-Rules`          | Present when using per-URL `rewriteRules`                                      |
| `X-Stoobly-Public-Directory-Path`  | Present when using per-URL `publicDirectoryPath`                               |
| `X-Stoobly-Response-Fixtures-Path` | Present when using per-URL `responseFixturesPath`                              |

#### Q: Why do I get "page is not defined" errors in Playwright?

**A:** Ensure you call `withPage(page)` in `beforeEach` before `enable()`.

**Example:**

```javascript
// BAD: Missing withPage()
test.beforeEach(async ({ page }, testInfo) => {
  await interceptor.enable(); // ERROR: page not set
});

// GOOD: Call withPage() first
test.beforeEach(async ({ page }, testInfo) => {
  await interceptor.withPage(page).enable(); // Correct
  interceptor.withTestTitle(testInfo.title);
});
```

#### Q: How do I handle TypeScript errors?

**A:** The library includes TypeScript definitions. Ensure your tsconfig.json includes the library.

**Example:**

```json
{
  "compilerOptions": {
    "types": ["@playwright/test", "stoobly"],
    "moduleResolution": "node",
    "esModuleInterop": true
  }
}
```

***

### Complete Examples

#### Q: What's a complete Playwright example with recording and mocking?

**A:** Here's a complete example showing recording and mocking workflows with an environment variable to toggle recording mode.

**Example:**

```javascript
import { test, expect } from '@playwright/test';
import Stoobly from 'stoobly';
import { InterceptMode, RecordPolicy, RecordOrder, RecordStrategy } from 'stoobly/constants';

// Toggle recording via environment variable
// Set STOOBLY_RECORD=true to enable recording, or leave unset/empty for mocking
const isRecording = process.env.STOOBLY_RECORD === 'true';

const stoobly = new Stoobly();
const interceptor = stoobly.playwrightInterceptor({
  urls: [new RegExp('https://api.example.com/.*')],
  record: {
    policy: RecordPolicy.All,
    order: RecordOrder.Overwrite,
    strategy: RecordStrategy.Full,
  }
});

test.describe('User API', () => {
  test.beforeEach(async ({ page }, testInfo) => {
    // Configure scenario per test suite
    interceptor.withScenarioKey('<SCENARIO-KEY>');

    // Set the page and test title
    interceptor.withPage(page).withTestTitle(testInfo.title);

    // Enable recording or mocking mode based on environment variable
    // This applies to all tests in the suite
    if (isRecording) {
      await interceptor.enable({ mode: InterceptMode.record });
    } else {
      await interceptor.enable({ mode: InterceptMode.mock });
    }
  });

  test('can fetch users', async ({ page }) => {
    await page.goto('https://example.com/users');

    // If recording: requests are captured for future use
    // If mocking: requests use previously recorded responses
    const users = await page.locator('.user-list').count();
    expect(users).toBeGreaterThan(0);

    // Verify the user list is displayed
    await expect(page.locator('.user-list')).toBeVisible();
  });

  test('can create user', async ({ page }) => {
    await page.goto('https://example.com/users/new');

    // Fill in the form
    await page.fill('input[name="name"]', 'Test User');
    await page.fill('input[name="email"]', 'test@example.com');
    await page.click('button[type="submit"]');

    // If recording: the POST request is captured
    // If mocking: uses previously recorded response
    await expect(page.locator('.success')).toBeVisible();
    await expect(page.locator('.success')).toContainText('User created successfully');
  });

  test('can update user', async ({ page }) => {
    await page.goto('https://example.com/users/1');

    // Edit user details
    await page.click('button:has-text("Edit")');
    await page.fill('input[name="name"]', 'Updated User');
    await page.click('button:has-text("Save")');

    // Verify update was successful
    await expect(page.locator('.success')).toBeVisible();
    await expect(page.locator('h1')).toContainText('Updated User');
  });
});
```

**Usage:**

```bash
# Run tests in mock mode (default - uses recorded responses)
npm test

# Run tests in record mode (captures new requests)
STOOBLY_RECORD=true npm test

# Or set in your .env file
echo "STOOBLY_RECORD=true" >> .env
```

**Workflow:**

1. **First run (recording):** Set `STOOBLY_RECORD=true` to capture all API requests and responses
2. **Subsequent runs (mocking):** Leave `STOOBLY_RECORD` unset to use recorded responses for fast, reliable tests
3. **Update recordings:** Set `STOOBLY_RECORD=true` again when APIs change to refresh the recorded data

#### Q: What's a complete Cypress example with recording and mocking?

**A:** Here's a complete example showing recording and mocking workflows with an environment variable to toggle recording mode.

**Example:**

```javascript
import Stoobly from 'stoobly';
import { InterceptMode, RecordPolicy, RecordOrder, RecordStrategy } from 'stoobly/constants';

// Toggle recording via environment variable
// Set STOOBLY_RECORD=true to enable recording, or leave unset/empty for mocking
const isRecording = Cypress.env('STOOBLY_RECORD') === true || process.env.STOOBLY_RECORD === 'true';

const stoobly = new Stoobly();
const interceptor = stoobly.cypressInterceptor({
  urls: [new RegExp('https://api.example.com/.*')],
  record: {
    policy: RecordPolicy.All,
    order: RecordOrder.Overwrite,
    strategy: RecordStrategy.Full,
  }
});

describe('User API', () => {
  beforeEach(() => {
    // Configure scenario per test suite
    interceptor.withScenarioKey('<SCENARIO-KEY>');

    // Enable recording or mocking mode based on environment variable
    // This applies to all tests in the suite
    if (isRecording) {
      interceptor.enable({ mode: InterceptMode.record });
    } else {
      interceptor.enable({ mode: InterceptMode.mock });
    }
  });

  it('can fetch users', () => {
    cy.visit('https://example.com/users');

    // If recording: requests are captured for future use
    // If mocking: requests use previously recorded responses
    cy.get('.user-list .user').should('have.length.greaterThan', 0);

    // Verify the user list is displayed
    cy.get('.user-list').should('be.visible');
  });

  it('can create user', () => {
    cy.visit('https://example.com/users/new');

    // Fill in the form
    cy.get('input[name="name"]').type('Test User');
    cy.get('input[name="email"]').type('test@example.com');
    cy.get('button[type="submit"]').click();

    // If recording: the POST request is captured
    // If mocking: uses previously recorded response
    cy.get('.success').should('be.visible');
    cy.get('.success').should('contain', 'User created successfully');
  });

  it('can update user', () => {
    cy.visit('https://example.com/users/1');

    // Edit user details
    cy.get('button:contains("Edit")').click();
    cy.get('input[name="name"]').clear().type('Updated User');
    cy.get('button:contains("Save")').click();

    // Verify update was successful
    cy.get('.success').should('be.visible');
    cy.get('h1').should('contain', 'Updated User');
  });
});
```

**Usage:**

```bash
# Run tests in mock mode (default - uses recorded responses)
npm test

# Run tests in record mode (captures new requests)
STOOBLY_RECORD=true npm test

# Or set in Cypress config (cypress.config.js)
export default defineConfig({
  env: {
    STOOBLY_RECORD: true
  }
});

# Or set in your .env file
echo "STOOBLY_RECORD=true" >> .env
```

**Workflow:**

1. **First run (recording):** Set `STOOBLY_RECORD=true` to capture all API requests and responses
2. **Subsequent runs (mocking):** Leave `STOOBLY_RECORD` unset to use recorded responses for fast, reliable tests
3. **Update recordings:** Set `STOOBLY_RECORD=true` again when APIs change to refresh the recorded data

***

### Quick Reference

#### Q: What are the key methods for the interceptor?

**A:** Here's a quick reference of the most common interceptor methods.

**Example:**

```javascript
import { InterceptMode, RecordPolicy, RecordOrder, RecordStrategy } from 'stoobly/constants';

const interceptor = stoobly.playwrightInterceptor(options);

// Enable interception
await interceptor.withPage(page).enable();
await interceptor.enable({ mode: InterceptMode.record }); // Recording mode

// Configure scenario
interceptor.withScenarioKey('key');
interceptor.withScenarioName('name');
interceptor.withSessionId('session-id');
interceptor.withTestTitle('test title');

// Configure recording
interceptor.withRecordPolicy(RecordPolicy.All);
interceptor.withRecordOrder(RecordOrder.Overwrite);
interceptor.withRecordStrategy(RecordStrategy.Full);

// Chainable intercept mode shortcuts
interceptor.withInterceptMode(InterceptMode.mock);
interceptor.withInterceptModeMock();
interceptor.withInterceptModeRecord();
interceptor.withInterceptModeReplay();

// Control interception
await interceptor.disable(); // Remove all interception
await interceptor.enable({ mode: InterceptMode.mock }); // Stop recording, keep mocking

// Change URLs
await interceptor.enable({ urls: [new RegExp('...')] });

// Deprecated aliases (still supported): apply() → enable(), clear() → disable()
```

#### Q: What constants are available?

**A:** Stoobly provides enums for record policies, orders, and strategies.

**Example:**

```javascript
import {
  RecordPolicy,
  RecordOrder,
  RecordStrategy,
  InterceptMode
} from 'stoobly/constants';

// Record Policies
RecordPolicy.All       // Record all requests
RecordPolicy.Found     // Record only if exists
RecordPolicy.NotFound  // Record only if new

// Record Orders
RecordOrder.Overwrite  // Replace existing
RecordOrder.Append     // Always create new

// Record Strategies
RecordStrategy.Full    // Complete data
RecordStrategy.Minimal // Essential data only

// Intercept Modes
InterceptMode.mock     // Mocking mode
InterceptMode.record   // Recording mode
InterceptMode.replay   // Replay mode
InterceptMode.test     // Testing mode
```


# Local

## Stoobly Scaffold Local Runtime E2E Testing - Questions & Answers

This document covers local runtime-specific E2E testing customization options for Stoobly scaffold. For general E2E testing topics, see [README.md](/faq/scaffold/e2e-testing). For Docker runtime E2E testing, see [docker.md](/faq/scaffold/e2e-testing/docker).

***

### Local Initial Setup

#### Q: How do I scaffold an app for Playwright E2E testing with local runtime?

**A:** Create an app with the `--plugin playwright` option and `--runtime local` to set up Playwright-specific configurations.

**Example:**

```bash
# Create app with Playwright
stoobly-agent scaffold app create my-e2e-tests \
  --plugin playwright \
  --runtime local
```

#### Q: How do I scaffold an app for Cypress E2E testing with local runtime?

**A:** Create an app with the `--plugin cypress` option and `--runtime local` to set up Cypress-specific configurations.

**Example:**

```bash
# Create app with Cypress
stoobly-agent scaffold app create my-cypress-tests \
  --plugin cypress \
  --runtime local
```

**Note:** With local runtime, there's no entrypoint service, so you'll run your tests directly on your machine with proxy configuration.

***

### Local Configuration Files

#### Q: What files should I modify to add my Playwright tests with local runtime?

**A:** Configure your Playwright tests to use Stoobly's proxy by setting environment variables or configuring the proxy in your Playwright config.

**Example - Set proxy environment variables:**

```bash
# Set proxy environment variables
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080

# Run your tests
npx playwright test
```

**Example - Create Playwright config:**

```javascript
// playwright.config.ts (in your project root)
import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    proxy: {
      server: 'http://localhost:8080',
    },
    ignoreHTTPSErrors: true,
  },
});
```

**Note:** `ignoreHTTPSErrors: true` covers the browser Playwright drives, but if your test process itself (or a Node dev server behind the proxy) makes HTTPS calls, Node needs to separately trust Stoobly's CA certificate — see the [CA Cert FAQ](/faq/ca-cert).

#### Q: What files should I modify to add my Cypress tests with local runtime?

**A:** Configure Cypress to use Stoobly's proxy by setting environment variables or configuring the proxy in your Cypress config.

**Example - Set proxy environment variables:**

```bash
# Set proxy environment variables
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080

# Run your tests
npx cypress run
```

**Example - Create Cypress config:**

```javascript
// cypress.config.js (in your project root)
const { defineConfig } = require('cypress');

module.exports = defineConfig({
  e2e: {
    env: {
      HTTP_PROXY: 'http://localhost:8080',
      HTTPS_PROXY: 'http://localhost:8080',
    },
  },
});
```

#### Q: How do I pass environment variables to my local tests?

**A:** Set environment variables in your shell or use a `.env` file that your test framework reads.

**Example:**

```bash
# Set environment variables before running tests
export BASE_URL=http://app.local
export API_URL=http://api.local
export TEST_USER_EMAIL=test@example.com
export TEST_USER_PASSWORD=testpass123
export NODE_ENV=test

# Run tests
npx playwright test
```

Or use a `.env` file:

```bash
# .env
BASE_URL=http://app.local
API_URL=http://api.local
TEST_USER_EMAIL=test@example.com
TEST_USER_PASSWORD=testpass123
NODE_ENV=test
```

***

### Running Local E2E Tests

**💡 Tip:** The examples below run each step manually across terminals for clarity. For day-to-day use, wrap `workflow up`/`down` and your test command into `package.json` scripts so a single `npm run test:mock` (etc.) handles bring-up, test run, and teardown — including correct CI exit-code propagation. See [JS Client — npm Scripts](/faq/scaffold/e2e-testing/js-client/npm-scripts).

#### Q: How do I record E2E test traffic with local runtime?

**A:** Use the record workflow to capture all HTTP requests made during your E2E tests.

**Example:**

```bash
# Start record workflow and enable recording (local runtime uses CLI commands, not Makefile)
stoobly-agent scaffold workflow up record
stoobly-agent intercept enable

# In another terminal, set proxy and run tests
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080
npx playwright test

# View recorded requests
stoobly-agent request list

# Create scenario from recorded requests
stoobly-agent scenario create "E2E User Flow"

# Stop workflow
stoobly-agent scaffold workflow down record
```

**Note:** Make commands (e.g., `make -f .stoobly/services/Makefile record`) are Docker-specific. Local runtime uses `stoobly-agent scaffold workflow up/down` commands directly.

#### Q: How do I run E2E tests with mocked responses using local runtime?

**A:** Use the mock workflow to run tests against recorded responses without hitting real APIs.

**Example:**

```bash
# Ensure you have recorded responses
stoobly-agent scenario list

# Start mock workflow and enable intercept
stoobly-agent scaffold workflow up mock
stoobly-agent intercept enable

# In another terminal, run tests with proxy environment variables
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080
npx playwright test

# Tests run against mocked responses
# No real API calls are made

# Stop workflow
stoobly-agent scaffold workflow down mock
```

#### Q: How do I run E2E tests with response validation using local runtime?

**A:** Use the test workflow to validate that responses match expected results.

**Example:**

```bash
# Start test workflow and enable intercept
stoobly-agent scaffold workflow up test
stoobly-agent intercept enable

# In another terminal, run tests with proxy environment variables
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080
npx playwright test

# Tests run with response validation
# Stoobly compares actual vs expected responses

# View test results (check logs in .stoobly/tmp/test/logs/)
cat .stoobly/tmp/test/logs/requests.json

# Stop workflow
stoobly-agent scaffold workflow down test
```

#### Q: How do I run E2E tests with local runtime?

**A:** Start the Stoobly workflow using CLI commands (not Makefile), then run your tests directly with proxy environment variables set.

#### Q: How do I run specific test files or suites with local runtime?

**A:** Use your test framework's command-line options to target specific tests.

**Example for Playwright:**

```bash
# Run specific test file
npx playwright test tests/login.spec.ts

# Run tests with specific tag
npx playwright test --grep @smoke

# Run tests in headed mode for debugging
npx playwright test --headed
```

**Example for Cypress:**

```bash
# Run specific spec
npx cypress run --spec "cypress/e2e/login.cy.js"

# Run with specific browser
npx cypress run --browser chrome

# Run with video recording
npx cypress run --video
```

***

### Local Debugging

#### Q: How do I view test output and logs with local runtime?

**A:** View logs from the workflow directory or check Stoobly agent logs directly.

**Example:**

```bash
# View logs from the workflow directory
cat .stoobly/tmp/test/logs/requests.json

# Or check Stoobly agent logs directly
stoobly-agent request list
```

#### Q: How do I debug failing local tests?

**A:** Enable debug mode in your test framework and increase logging verbosity.

**Example for Playwright:**

```bash
# Enable debug mode
export DEBUG=pw:api
export PWDEBUG=1

# Run tests in headed mode
npx playwright test --headed --debug
```

**Example for Cypress:**

```bash
# Run in interactive mode
npx cypress open

# Or with debug logging
DEBUG=cypress:* npx cypress run
```

#### Q: How do I save test artifacts (screenshots, videos) with local runtime?

**A:** Configure your test framework to save artifacts to a local directory.

**Example for Playwright:**

```javascript
// playwright.config.ts
export default defineConfig({
  use: {
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },
  outputDir: 'test-results',
});
```

**Example for Cypress:**

```javascript
// cypress.config.js
module.exports = defineConfig({
  e2e: {
    screenshotOnRunFailure: true,
    video: true,
  },
});
```

***

### Local Best Practices

#### Q: Should I record once and mock for all subsequent runs with local runtime?

**A:** Yes, this is the recommended approach for fast, reliable E2E tests that don't depend on external APIs.

**Example:**

```bash
# Step 1: Create scenario from recordings
stoobly-agent scenario create "User Journey - Login to Checkout"

# Step 2: Record once (against real APIs)
stoobly-agent scaffold workflow up record
stoobly-agent intercept enable

# Run tests in another terminal, then:
stoobly-agent scaffold workflow down record

# Step 3: Snapshot for version control
stoobly-agent scenario snapshot user-journey --decode
git add .stoobly/snapshots/ && git commit -m "Add E2E test snapshots"

# Step 4: All future runs use mocks (fast, no external dependencies)
stoobly-agent scaffold workflow up mock
stoobly-agent intercept enable
# Run tests in another terminal
```

#### Q: How do I organize E2E tests by feature with local runtime?

**A:** Create separate services or custom workflows for different test suites.

**Example:**

```bash
# Create service for auth tests
stoobly-agent scaffold service create auth-tests \
  --workflow test

# Create service for checkout tests
stoobly-agent scaffold service create checkout-tests \
  --workflow test

# Run specific test suite
stoobly-agent scaffold workflow up test --service auth-tests
```

***

### Local CI/CD Integration

#### Q: Can I use local runtime in CI/CD for E2E testing?

**A:** Yes, if your CI environment has Python and stoobly-agent installed, local runtime can be faster for E2E tests.

**Example:**

```bash
#!/bin/bash
# CI/CD script with local runtime

# Install Stoobly
pipx install stoobly-agent

# Install Stoobly ca-certs
sudo stoobly-agent ca-cert install

# Use local runtime
stoobly-agent scaffold workflow up test

# Cleanup
stoobly-agent scaffold workflow down test
```

#### Q: How do I test with local runtime in CI/CD?

**A:** Install stoobly-agent and use CLI commands in your CI/CD pipeline.

**Example:**

```yaml
# .github/workflows/test.yml
name: Test with Local

jobs:
  test-local:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install stoobly-agent
        run: pipx install stoobly-agent
      - name: Test with Local
        run: |
          stoobly-agent scaffold workflow up test
          stoobly-agent scaffold workflow down test
```

***

### Local Advanced Configuration

#### Q: How do I access test fixtures and data with local runtime?

**A:** Reference fixtures and test data using relative paths from your project root. No volume mounting is needed since everything runs on your local machine.

**Example:**

```javascript
// tests/login.spec.ts
import { test, expect } from '@playwright/test';
import fs from 'fs';
import path from 'path';

test('user can login', async ({ page }) => {
  // Read test data from local file
  const testData = JSON.parse(
    fs.readFileSync(path.join(__dirname, '../test-data/users.json'), 'utf8')
  );
  
  await page.goto('/login');
  await page.fill('[name="email"]', testData.email);
  await page.fill('[name="password"]', testData.password);
  await page.click('button[type="submit"]');
});
```


# Runtime

## Stoobly Scaffold Runtime Options - Questions & Answers

The `--runtime` option when creating a scaffold app determines whether workflows run locally on your machine or in Docker containers. **By default, `scaffold app create` uses local runtime** (no `--runtime` option needed). You can only specify one runtime option at a time: either `local` or `docker`, but not both.

**📚 Related Documentation:**

* For Docker-specific runtime details, see [docker.md](/faq/scaffold/runtime/docker)
* For local runtime-specific details, see [local.md](/faq/scaffold/runtime/local)

***

### Understanding Runtime Options

#### Q: What runtime options are available for scaffold apps?

**A:** Scaffold supports two runtime options: `local` (native execution on your machine) and `docker` (containerized execution). **`scaffold app create` defaults to local runtime** - you don't need to specify `--runtime local` unless you want to be explicit.

**Example:**

```bash
# Local runtime (default - no --runtime option needed)
stoobly-agent scaffold app create my-app

# Or explicitly specify local runtime (optional, same as default)
stoobly-agent scaffold app create my-app --runtime local

# Docker runtime (must be explicitly specified)
stoobly-agent scaffold app create my-app --runtime docker
```

#### Q: What's the difference between local and Docker runtime?

**A:** Local runtime executes workflows directly on your machine using your installed Python and dependencies, while Docker runtime runs workflows in isolated containers with consistent environments.

**Example:**

```bash
# Docker: Isolated, consistent, requires Docker installed
stoobly-agent scaffold app create my-app --runtime docker

# Local: Uses your machine's Python, faster startup, no Docker needed
stoobly-agent scaffold app create my-app --runtime local
```

#### Q: Which runtime option should I choose?

**A:** **Local runtime is the default** and is recommended for faster iteration and simpler setup. Use Docker runtime for team consistency and isolation. You can only choose one runtime option per app.

**Example:**

```bash
# Local runtime (default - no --runtime option needed)
stoobly-agent scaffold app create my-app

# Or explicitly specify local runtime
stoobly-agent scaffold app create my-app --runtime local

# Docker runtime (must be explicitly specified)
stoobly-agent scaffold app create my-app --runtime docker

# Note: You cannot use both --runtime local and --runtime docker together
```

#### Q: What's the usage difference between local and Docker runtime?

**A:** The main difference is in the commands you use to run workflows. Local runtime uses direct CLI commands, while Docker runtime uses Makefile commands.

**Example:**

```bash
# Local runtime (default)
stoobly-agent scaffold app create my-app

# Start workflow with local runtime
stoobly-agent scaffold workflow up record
stoobly-agent scaffold workflow up mock
stoobly-agent scaffold workflow up test

# Stop workflow
stoobly-agent scaffold workflow down record

# Docker runtime
stoobly-agent scaffold app create my-app --runtime docker

# Start workflow with Docker runtime
make -f .stoobly/services/.Makefile record
make -f .stoobly/services/.Makefile mock
make -f .stoobly/services/.Makefile test

# Stop workflow
make -f .stoobly/services/.Makefile record/down
make -f .stoobly/services/.Makefile mock/down
make -f .stoobly/services/.Makefile test/down
```

**For more details:**

* Docker runtime: See [docker.md](/faq/scaffold/runtime/docker)
* Local runtime: See [local.md](/faq/scaffold/runtime/local)

***

### Switching From One Runtime To Another

#### Q: Do both runtimes use the same configuration?

**A:** Yes, both runtimes share the same service configurations, workflows, and recorded data. However, you can only choose one runtime option when creating an app.

**Example:**

```bash
# Create app with local runtime (default)
stoobly-agent scaffold app create my-app

# Or create app with Docker runtime
stoobly-agent scaffold app create my-app --runtime docker

# Add service (works with either runtime)
stoobly-agent scaffold service create api --hostname api.local

# Use Docker runtime (if app was created with --runtime docker)
make -f .stoobly/services/.Makefile test

# Or use local runtime (if app was created with --runtime local or default)
stoobly-agent scaffold workflow up test
```

#### Q: Can I switch between local and Docker runtime after creating the app?

**A:** Yes, you can recreate the app with a different runtime option. Note that you can only use one runtime option at a time.

**Example:**

```bash
# Initially created with Docker
stoobly-agent scaffold app create my-app --runtime docker

# Later, recreate to switch to local runtime
stoobly-agent scaffold app create my-app --runtime local
# (This updates the configuration without deleting data)

# Note: You cannot use both --runtime local and --runtime docker together
```

***

### Runtime-Specific Workflows

#### Q: How do I use a specific runtime?

**A:** The runtime is determined when you create the app. Use CLI commands for local runtime, or Makefile commands for Docker runtime.

* **Docker runtime:** See [docker.md](/faq/scaffold/runtime/docker) for details.
* **Local runtime:** See [local.md](/faq/scaffold/runtime/local) for details.

***

### Performance Considerations

#### Q: Which runtime is faster for development?

**A:** Local runtime typically has faster startup times, while Docker provides better isolation and consistency.

**Example:**

```bash
# Local: Faster startup
time stoobly-agent scaffold workflow up test
# ~2-5 seconds

# Docker: Slower startup but isolated
time make -f .stoobly/services/.Makefile test
# ~10-30 seconds (first time, includes image pull)
```

#### Q: Does Docker runtime use more resources?

**A:** Yes, Docker adds overhead for containerization, but provides better isolation and cleanup.

**Example:**

```bash
# Docker: More memory/CPU but isolated
make -f .stoobly/services/.Makefile test
docker stats  # View resource usage

# Local: Less overhead but shares system resources
stoobly-agent scaffold workflow up test
```

**For optimization tips:**

* Docker runtime: See [docker.md](/faq/scaffold/runtime/docker) for performance optimization.
* Local runtime: Generally requires no special optimization.

***

### Team Collaboration with Different Runtimes

#### Q: How do I set up a project that works for team members with different preferences?

**A:** Choose one runtime for the project. Team members can recreate the app with their preferred runtime if needed, as configurations are shared.

**Example:**

```bash
# Project setup (team lead) - choose one runtime
stoobly-agent scaffold app create team-project --runtime docker
stoobly-agent scaffold service create api --hostname api.local

# Document in README:
# Docker users: make -f .stoobly/services/.Makefile test
# Local users: Recreate with --runtime local, then use: stoobly-agent scaffold workflow up test
```

#### Q: How do I ensure consistency when team members use different runtimes?

**A:** Use the same service configurations and share recorded data via version control.

**Example:**

```bash
# Both runtimes share the same data
git add .stoobly/
git commit -m "Add scaffold configuration and snapshots"

# Team member A (Docker)
git pull
make -f .stoobly/services/.Makefile mock

# Team member B (Local)
git pull
stoobly-agent scaffold workflow up mock
```

#### Q: Can local and Docker users work on the same project simultaneously?

**A:** If the app was created with one runtime, team members using a different runtime will need to recreate the app with their preferred runtime. They should use different workflow namespaces to avoid conflicts.

**Note:** Namespaces are only supported by test workflows and custom workflows based on the test workflow template.

**Example:**

```bash
# Docker user (app created with --runtime docker)
make -f .stoobly/services/.Makefile test namespace=docker-dev

# Local user (recreates app with --runtime local, different machine or namespace)
stoobly-agent scaffold app create my-app --runtime local
stoobly-agent scaffold workflow up test --namespace local-dev
```

***

### Migration Between Runtimes

#### Q: How do I migrate between runtimes?

**A:** Recreate the app with the desired runtime and use the appropriate commands.

* **From Docker to local:** See [local.md](/faq/scaffold/runtime/local) for migration steps.
* **From local to Docker:** See [docker.md](/faq/scaffold/runtime/docker) for migration steps.

#### Q: Will my recorded data work with both runtimes?

**A:** Yes, recorded data is stored in `.stoobly/` and works with both runtimes.

**Example:**

```bash
# Record with Docker
make -f .stoobly/services/.Makefile record
make -f .stoobly/services/.Makefile intercept/enable
# ... make requests ...
make -f .stoobly/services/.Makefile record/down

# Mock with local (uses same data)
stoobly-agent scaffold workflow up mock
```

***

### Quick Reference

#### Q: What's a quick comparison of local vs Docker runtime?

**A:** Here's a side-by-side comparison:

**Local Runtime:**

* ✅ Faster startup
* ✅ Simpler debugging
* ✅ Less resource usage
* ✅ No Docker required
* ❌ Requires Python 3.12+
* ❌ Less isolation
* ❌ Environment differences possible

**Docker Runtime:**

* ✅ Consistent across all environments
* ✅ Complete isolation
* ✅ Easy cleanup
* ✅ Works on Windows, Mac, Linux
* ❌ Slower startup
* ❌ Requires Docker installed
* ❌ More resource usage

**Example:**

```bash
# Choose based on your needs:

# Speed & simplicity → Local
stoobly-agent scaffold app create my-app --runtime local

# Team consistency & isolation → Docker
stoobly-agent scaffold app create my-app --runtime docker
```

#### Q: What's the recommended setup for a new team project?

**A:** Choose one runtime based on your team's needs. Local (default) offers faster iteration, while Docker provides consistency.

**Example:**

```bash
# Recommended team setup - choose one runtime
stoobly-agent scaffold app create team-project \
  --runtime docker \
  --plugin cypress \
  --proxy-port 8080 \
  --ui-port 4200

# Or use local runtime (default)
stoobly-agent scaffold app create team-project \
  --plugin cypress \
  --proxy-port 8080 \
  --ui-port 4200

# Add services
stoobly-agent scaffold service create api --hostname api.local
stoobly-agent scaffold service create frontend --hostname frontend.local

# Document the chosen runtime in README
# Docker: make -f .stoobly/services/.Makefile test
# Local: stoobly-agent scaffold workflow up test
```


# Docker

## Stoobly Scaffold Docker Runtime - Questions & Answers

This document covers Docker-specific runtime options for Stoobly scaffold. For general runtime topics, see [README.md](/faq/scaffold/runtime). For local runtime, see [local.md](/faq/scaffold/runtime/local).

***

### Docker Runtime Overview

#### Q: What are the benefits of using Docker runtime?

**A:** Docker provides environment consistency across team members, dependency isolation, easy cleanup, and works the same on all operating systems.

**Example:**

```bash
stoobly-agent scaffold app create my-app --runtime docker

# All team members get the same environment
make -f .stoobly/services/.Makefile record
```

#### Q: What are the requirements for Docker runtime?

**A:** You need Docker installed and running on your machine. The Docker daemon must be accessible.

**Example:**

```bash
# Verify Docker is installed and running
docker --version
docker ps

# Create Docker-based scaffold
stoobly-agent scaffold app create my-app --runtime docker
```

#### Q: How do I specify a custom Docker socket path?

**A:** Use the `--docker-socket-path` option when creating the app.

**Example:**

```bash
stoobly-agent scaffold app create my-app \
  --runtime docker \
  --docker-socket-path /var/run/docker.sock
```

#### Q: How do Docker-based workflows work?

**A:** Docker workflows use docker-compose to orchestrate containers for stoobly-agent, your services, and any dependencies, providing complete isolation.

**Example:**

```bash
# Create Docker-based app
stoobly-agent scaffold app create my-app --runtime docker

# Start workflow (runs in containers)
make -f .stoobly/services/.Makefile record

# View running containers
docker ps

# Stop workflow (cleans up containers)
make -f .stoobly/services/.Makefile record/down
```

#### Q: What files are created when I scaffold an app with Docker runtime?

**A:** Scaffolding creates a `.stoobly/services/` directory in the current directory with Docker configurations, Makefile, service definitions, and workflow templates.

**Example:**

```bash
stoobly-agent scaffold app create my-app --runtime docker
ls -la .stoobly/services/
# build .docker-compose.base.yml .Dockerfile.context gateway Makefile
```

#### Q: Can I use Docker runtime on Windows, Mac, and Linux?

**A:** Yes, Docker runtime works consistently across all platforms as long as Docker Desktop (Windows/Mac) or Docker Engine (Linux) is installed.

**Example:**

```bash
# Same command works on all platforms
stoobly-agent scaffold app create my-app --runtime docker
make -f .stoobly/services/.Makefile record
```

#### Q: How do I troubleshoot Docker runtime issues?

**A:** Check Docker is running, verify permissions, and review container logs.

**Example:**

```bash
# Check Docker status
docker ps

# View container logs
make -f .stoobly/services/.Makefile mock/logs

# Check intercepted request logs
make -f .stoobly/services/.Makefile mock/request/logs

# Follow logs in real time (-f / --follow, Ctrl-C to stop)
make -f .stoobly/services/.Makefile mock/request/logs options="--follow"

# Filter by log level
make -f .stoobly/services/.Makefile mock/request/logs options="--level error"
```

***

### Docker Workflows

#### Q: How do I explicitly use Docker runtime for a workflow?

**A:** Use the Makefile commands, which are configured for Docker execution.

**Example:**

```bash
# Docker runtime via Makefile
make -f .stoobly/services/.Makefile record
make -f .stoobly/services/.Makefile mock
make -f .stoobly/services/.Makefile test
```

#### Q: How do I use Docker runtime?

**A:** Create the app with `--runtime docker` and use Makefile commands for workflows.

**Example:**

```bash
# App created with Docker runtime
stoobly-agent scaffold app create my-app --runtime docker
make -f .stoobly/services/.Makefile record
```

***

### Docker Performance

#### Q: How do I optimize Docker runtime performance?

**A:** Use local Docker images, enable BuildKit, and allocate sufficient resources to Docker.

**Example:**

```bash
# Use local images (faster)
export STOOBLY_IMAGE_USE_LOCAL=1
make -f .stoobly/services/.Makefile record

# Enable Docker BuildKit
export DOCKER_BUILDKIT=1
make -f .stoobly/services/.Makefile record
```

***

### Docker Migration

#### Q: How do I migrate from local to Docker runtime?

**A:** Recreate the app with Docker runtime and start using Makefile commands.

**Example:**

```bash
# Currently using local (default)
# Recreate with Docker runtime
stoobly-agent scaffold app create my-app --runtime docker

# Now use Docker runtime commands
make -f .stoobly/services/.Makefile record
```

***

### Getting Started with Make Commands

#### Q: Where is the Makefile located after scaffolding?

**A:** The Makefile is automatically created at `.stoobly/services/.Makefile` in your application directory after scaffolding with `--runtime docker`.

**Example:**

```bash
cd /path/to/your-app
ls .stoobly/services/.Makefile
```

#### Q: How do I run make commands from my project root?

**A:** Use the `-f` flag to specify the Makefile path, or create a symlink in your project root.

**Example:**

```bash
# Option 1: Specify the Makefile path
make -f .stoobly/services/.Makefile record

# Option 2: Create a symlink (one-time setup)
ln -s .stoobly/services/.Makefile Makefile
make record
```

***

### Recording Workflow

#### Q: How do I start a recording workflow?

**A:** Use `make record` to start the recording workflow, which sets up the proxy to capture HTTP requests. Use `make intercept/enable` to enable intercept to start recording.

**Example:**

```bash
make -f .stoobly/services/.Makefile record
make -f .stoobly/services/.Makefile intercept/enable
```

#### Q: How do I stop a recording workflow?

**A:** Use `make record/down` to stop and clean up the recording workflow.

**Example:**

```bash
make -f .stoobly/services/.Makefile record/down
```

#### Q: How do I view logs from the recording workflow?

**A:** Use `make record/logs` to display logs from all services in the recording workflow.

**Example:**

```bash
make -f .stoobly/services/.Makefile record/logs
```

#### Q: How do I view intercepted request logs from the recording workflow?

**A:** Use `make record/request/logs` to list intercepted request log entries. Pass filter or follow flags via the `options` variable.

**Examples:**

```bash
# List intercepted request log entries
make -f .stoobly/services/.Makefile record/request/logs

# Follow logs in real time (-f / --follow, Ctrl-C to stop)
make -f .stoobly/services/.Makefile record/request/logs options="--follow"

# Filter by HTTP method
make -f .stoobly/services/.Makefile record/request/logs options="--method post"

# Filter by URL substring
make -f .stoobly/services/.Makefile record/request/logs options="--url /api/users"

# Filter by HTTP status code
make -f .stoobly/services/.Makefile record/request/logs options="--status-code 500"

# Filter by log level
make -f .stoobly/services/.Makefile record/request/logs options="--level error"

# Output as JSON
make -f .stoobly/services/.Makefile record/request/logs options="--format json"

# Combine filters with follow
make -f .stoobly/services/.Makefile record/request/logs options="--follow --level error --method post"

# Print the log file path
make -f .stoobly/services/.Makefile record/request/logs/path

# Clear the log
make -f .stoobly/services/.Makefile record/request/logs/delete
```

#### Q: How do I list services in the recording workflow?

**A:** Use `make record/services` to display all configured services for the recording workflow.

**Example:**

```bash
make -f .stoobly/services/.Makefile record/services
```

#### Q: How do I view the recorded requests report?

**A:** Use `make record/report` to display a list of all intercepted and recorded requests.

**Example:**

```bash
make -f .stoobly/services/.Makefile record/report
```

***

### Mock Workflow

#### Q: How do I start a mock workflow?

**A:** Use `make mock` to start the mock workflow, which serves mocked responses based on recorded data. Use `make intercept/enable` to enable intercept to start mocking.

**Example:**

```bash
make -f .stoobly/services/.Makefile mock
make -f .stoobly/services/.Makefile intercept/enable
```

#### Q: How do I stop a mock workflow?

**A:** Use `make mock/down` to stop and clean up the mock workflow.

**Example:**

```bash
make -f .stoobly/services/.Makefile mock/down
```

#### Q: How do I view logs from the mock workflow?

**A:** Use `make mock/logs` to display logs from all services in the mock workflow.

**Example:**

```bash
make -f .stoobly/services/.Makefile mock/logs
```

#### Q: How do I view intercepted request logs from the mock workflow?

**A:** Use `make mock/request/logs` to list intercepted request log entries. Pass filter or follow flags via the `options` variable.

**Examples:**

```bash
# List intercepted request log entries
make -f .stoobly/services/.Makefile mock/request/logs

# Follow logs in real time (-f / --follow, Ctrl-C to stop)
make -f .stoobly/services/.Makefile mock/request/logs options="--follow"

# Filter by HTTP method
make -f .stoobly/services/.Makefile mock/request/logs options="--method post"

# Filter by URL substring
make -f .stoobly/services/.Makefile mock/request/logs options="--url /api/users"

# Filter by HTTP status code
make -f .stoobly/services/.Makefile mock/request/logs options="--status-code 500"

# Filter by log level
make -f .stoobly/services/.Makefile mock/request/logs options="--level error"

# Filter by log message
make -f .stoobly/services/.Makefile mock/request/logs options="--message \"Mock failure\""

# Output as JSON
make -f .stoobly/services/.Makefile mock/request/logs options="--format json"

# Combine filters with follow
make -f .stoobly/services/.Makefile mock/request/logs options="--follow --level error --method post"

# Print the log file path
make -f .stoobly/services/.Makefile mock/request/logs/path

# Clear the log
make -f .stoobly/services/.Makefile mock/request/logs/delete
```

#### Q: How do I list services in the mock workflow?

**A:** Use `make mock/services` to display all configured services for the mock workflow.

**Example:**

```bash
make -f .stoobly/services/.Makefile mock/services
```

#### Q: How do I view the mock requests report?

**A:** Use `make mock/report` to display a list of all mocked requests.

**Example:**

```bash
make -f .stoobly/services/.Makefile mock/report
```

***

### Test Workflow

#### Q: How do I start a test workflow?

**A:** Use `make test` to start the test workflow, which runs automated tests against your services. Use `make intercept/enable` to enable intercept to start testing.

**Example:**

```bash
make -f .stoobly/services/.Makefile test
make -f .stoobly/services/.Makefile intercept/enable
```

#### Q: How do I stop a test workflow?

**A:** Use `make test/down` to stop and clean up the test workflow.

**Example:**

```bash
make -f .stoobly/services/.Makefile test/down
```

#### Q: How do I view logs from the test workflow?

**A:** Use `make test/logs` to display logs from all services in the test workflow.

**Example:**

```bash
make -f .stoobly/services/.Makefile test/logs
```

#### Q: How do I view intercepted request logs from the test workflow?

**A:** Use `make test/request/logs` to list intercepted request log entries. Pass filter or follow flags via the `options` variable.

**Examples:**

```bash
# List intercepted request log entries
make -f .stoobly/services/.Makefile test/request/logs

# Follow logs in real time (-f / --follow, Ctrl-C to stop)
make -f .stoobly/services/.Makefile test/request/logs options="--follow"

# Filter by HTTP method
make -f .stoobly/services/.Makefile test/request/logs options="--method post"

# Filter by URL substring
make -f .stoobly/services/.Makefile test/request/logs options="--url /api/users"

# Filter by HTTP status code
make -f .stoobly/services/.Makefile test/request/logs options="--status-code 500"

# Filter by log level
make -f .stoobly/services/.Makefile test/request/logs options="--level error"

# Filter by test title
make -f .stoobly/services/.Makefile test/request/logs options="--test-title \"my test\""

# Output as JSON
make -f .stoobly/services/.Makefile test/request/logs options="--format json"

# Combine filters with follow
make -f .stoobly/services/.Makefile test/request/logs options="--follow --level error --method post"

# Print the log file path
make -f .stoobly/services/.Makefile test/request/logs/path

# Clear the log
make -f .stoobly/services/.Makefile test/request/logs/delete
```

#### Q: How do I list services in the test workflow?

**A:** Use `make test/services` to display all configured services for the test workflow.

**Example:**

```bash
make -f .stoobly/services/.Makefile test/services
```

#### Q: How do I view the test requests report?

**A:** Use `make test/report` to display a list of all test requests and results.

**Example:**

```bash
make -f .stoobly/services/.Makefile test/report
```

***

### Scenario Management

#### Q: How do I create a scenario using make?

**A:** Use `make scenario/create` with the `name` variable to create a new scenario.

**Example:**

```bash
make -f .stoobly/services/.Makefile scenario/create name="User Login Flow"
```

#### Q: How do I list all scenarios using make?

**A:** Use `make scenario/list` to display all available scenarios.

**Example:**

```bash
make -f .stoobly/services/.Makefile scenario/list
```

#### Q: How do I delete a scenario using make?

**A:** Use `make scenario/delete` with the `key` variable to delete a specific scenario.

**Example:**

```bash
make -f .stoobly/services/.Makefile scenario/delete key=<SCENARIO-KEY>
```

#### Q: How do I snapshot a scenario using make?

**A:** Use `make scenario/snapshot` with the `key` variable to create committable files for a scenario.

**Example:**

```bash
make -f .stoobly/services/.Makefile scenario/snapshot key=<SCENARIO-KEY>
```

#### Q: How do I reset a scenario to its snapshot state?

**A:** Use `make scenario/reset` with the `key` variable to restore a scenario from its snapshot.

**Example:**

```bash
make -f .stoobly/services/.Makefile scenario/reset key=<SCENARIO-KEY>
```

#### Q: How do I overwrite a scenario using make?

**A:** Use `make scenario/overwrite` with the `key` variable to overwrite an existing scenario.

**Example:**

```bash
make -f .stoobly/services/.Makefile scenario/overwrite key=<SCENARIO-KEY>
```

***

### Certificate Management

#### Q: How do I install the CA certificate using make?

**A:** The CA certificate is automatically installed when you start a workflow, but you can manually trigger it with `make ca-cert/install`.

**Example:**

```bash
make -f .stoobly/services/.Makefile ca-cert/install
```

#### Q: How do I skip the CA certificate installation prompt?

**A:** Set the `STOOBLY_CA_CERTS_INSTALL_CONFIRM` environment variable to `y` before running the workflow.

**Example:**

```bash
export STOOBLY_CA_CERTS_INSTALL_CONFIRM=y
make -f .stoobly/services/.Makefile record
```

***

### Hostname Management

#### Q: How do I skip the hostname installation prompt?

**A:** Set the `STOOBLY_HOSTNAME_INSTALL_CONFIRM` environment variable to `y` to automatically confirm hostname installation.

**Example:**

```bash
export STOOBLY_HOSTNAME_INSTALL_CONFIRM=y
make -f .stoobly/services/.Makefile record
```

#### Q: How do I prevent hostname installation?

**A:** Set the `STOOBLY_HOSTNAME_INSTALL_CONFIRM` environment variable to `n` to skip hostname installation.

**Example:**

```bash
export STOOBLY_HOSTNAME_INSTALL_CONFIRM=n
make -f .stoobly/services/.Makefile mock
```

***

### Intercept Management

#### Q: How do I enable intercept mode using make?

**A:** Use `make intercept/enable` with an optional `scenario_key` to enable request interception.

**Example:**

```bash
make -f .stoobly/services/.Makefile intercept/enable scenario_key=<SCENARIO-KEY>
```

#### Q: How do I disable intercept mode using make?

**A:** Use `make intercept/disable` to turn off request interception.

**Example:**

```bash
make -f .stoobly/services/.Makefile intercept/disable
```

***

### Environment Variables & Configuration

#### Q: How do I specify a custom application directory?

**A:** Set the `STOOBLY_APP_DIR` environment variable to point to your application directory.

**Example:**

```bash
export STOOBLY_APP_DIR=/path/to/my-app
make -f .stoobly/services/.Makefile record
```

#### Q: How do I use a custom .env file with workflows?

**A:** Set the `STOOBLY_DOTENV_FILE` environment variable to specify your .env file path.

**Example:**

```bash
export STOOBLY_DOTENV_FILE=/path/to/custom.env
make -f .stoobly/services/.Makefile mock
```

#### Q: How do I specify custom CA certificate directory?

**A:** Set the `STOOBLY_CA_CERTS_DIR` environment variable to your custom certificate directory.

**Example:**

```bash
export STOOBLY_CA_CERTS_DIR=/path/to/certs
make -f .stoobly/services/.Makefile record
```

#### Q: How do I pass additional service options to workflows?

**A:** Set the `STOOBLY_WORKFLOW_SERVICE_OPTIONS` environment variable with your custom options.

**Example:**

```bash
export STOOBLY_WORKFLOW_SERVICE_OPTIONS="--service api --service database"
make -f .stoobly/services/.Makefile record
```

#### Q: How do I specify a custom context directory?

**A:** Set the `STOOBLY_CONTEXT_DIR` environment variable to your desired context directory.

**Example:**

```bash
export STOOBLY_CONTEXT_DIR=/path/to/context
make -f .stoobly/services/.Makefile test
```

***

### Advanced Workflow Options

#### Q: How do I pass additional options to workflow up commands?

**A:** Use the `options` variable to pass extra options to the workflow.

**Example:**

```bash
make -f .stoobly/services/.Makefile record options="--detach"
```

#### Q: How do I run a workflow with a custom namespace?

**A:** Use the `namespace` variable to specify a custom workflow namespace.

**Note:** Namespaces are only supported by test workflows and custom workflows based on the test workflow template. Record and mock workflows do not support namespaces.

**Example:**

```bash
make -f .stoobly/services/.Makefile test namespace=my-custom-namespace
```

#### Q: How do I filter services when starting a workflow?

**A:** Set the `STOOBLY_WORKFLOW_SERVICE_OPTIONS` environment variable to specify which services to include.

**Example:**

```bash
export STOOBLY_WORKFLOW_SERVICE_OPTIONS="--service api --service frontend"
make -f .stoobly/services/.Makefile mock
```

***

### Combining Multiple Environment Variables

#### Q: How do I run a fully automated workflow without any prompts?

**A:** Set both hostname and CA certificate confirmation environment variables before running the workflow.

**Example:**

```bash
export STOOBLY_HOSTNAME_INSTALL_CONFIRM=y
export STOOBLY_CA_CERTS_INSTALL_CONFIRM=y
make -f .stoobly/services/.Makefile record
```

#### Q: How do I run a workflow with custom directories and environment?

**A:** Set multiple environment variables to customize all aspects of the workflow.

**Example:**

```bash
export STOOBLY_APP_DIR=/path/to/app
export STOOBLY_DOTENV_FILE=/path/to/.env.production
export STOOBLY_WORKFLOW_SERVICE_OPTIONS="--service api"
make -f .stoobly/services/.Makefile mock
```

***

### Docker Runtime Troubleshooting

#### Q: How do I check if stoobly-agent is installed?

**A:** The Makefile automatically checks and installs stoobly-agent via pipx if needed. You can manually trigger this with `make stoobly/install`.

**Example:**

```bash
make -f .stoobly/services/.Makefile stoobly/install
```

#### Q: How do I verify Python version compatibility?

**A:** Use `make python/validate` to check if you have a compatible Python version (3.12, 3.13, or 3.14).

**Example:**

```bash
make -f .stoobly/services/.Makefile python/validate
```

#### Q: What do I do if pipx is not installed?

**A:** The Makefile automatically installs pipx if it's missing. You can manually trigger this with `make pipx/install`.

**Example:**

```bash
make -f .stoobly/services/.Makefile pipx/install
```

#### Q: How do I view what services are configured?

**A:** Use the workflow-specific services command to list all configured services.

**Example:**

```bash
make -f .stoobly/services/.Makefile record/services
make -f .stoobly/services/.Makefile mock/services
make -f .stoobly/services/.Makefile test/services
```

#### Q: How do I validate my service configuration?

**A:** Use `scaffold service show` to view the current configuration.

**Example:**

```bash
stoobly-agent scaffold service show api
```

#### Q: What do I do if a workflow fails to start?

**A:** Check the logs for errors and verify service configurations.

**Example:**

```bash
# View logs
make -f .stoobly/services/.Makefile record/logs

# Verify services
make -f .stoobly/services/.Makefile record/services

# Check Docker containers
docker ps
```

***

### Docker Quick Reference

#### Q: What are the most common make commands I'll use?

**A:** Here's a quick reference of the most frequently used commands:

**Example:**

```bash
# Start workflows (then enable intercept)
make -f .stoobly/services/.Makefile record    # Start recording
make -f .stoobly/services/.Makefile intercept/enable

make -f .stoobly/services/.Makefile mock      # Start mocking
make -f .stoobly/services/.Makefile intercept/enable

make -f .stoobly/services/.Makefile test      # Start testing
make -f .stoobly/services/.Makefile intercept/enable

# Stop workflows
make -f .stoobly/services/.Makefile record/down
make -f .stoobly/services/.Makefile mock/down
make -f .stoobly/services/.Makefile test/down

# View logs
make -f .stoobly/services/.Makefile record/logs
make -f .stoobly/services/.Makefile mock/logs
make -f .stoobly/services/.Makefile test/logs

# Manage scenarios
make -f .stoobly/services/.Makefile scenario/list
make -f .stoobly/services/.Makefile scenario/create name="My Scenario"
make -f .stoobly/services/.Makefile scenario/snapshot key=<SCENARIO-KEY>

# View reports
make -f .stoobly/services/.Makefile record/report
make -f .stoobly/services/.Makefile mock/report
```

#### Q: How do I create an alias for easier make command usage?

**A:** Add an alias to your shell configuration file for convenience.

**Example:**

```bash
# Add to ~/.bashrc or ~/.zshrc
alias smake='make -f .stoobly/services/.Makefile'

# Then use it like:
smake record
smake mock/down
smake scenario/list
```


# Local

## Stoobly Scaffold Local Runtime - Questions & Answers

This document covers local runtime-specific options for Stoobly scaffold. For general runtime topics, see [README.md](/faq/scaffold/runtime). For Docker runtime, see [docker.md](/faq/scaffold/runtime/docker).

***

### Local Runtime Overview

#### Q: What are the benefits of using local runtime?

**A:** Local runtime offers faster startup times, simpler debugging, direct access to your filesystem, and no Docker dependency.

**Example:**

```bash
stoobly-agent scaffold app create my-app --runtime local

# Faster startup, no container overhead
stoobly-agent scaffold workflow up test
```

#### Q: What are the requirements for local runtime?

**A:** You need Python 3.12, 3.13, or 3.14 installed, and stoobly-agent installed via pipx.

**Example:**

```bash
# Verify Python version
python3 --version  # Should be 3.12, 3.13, or 3.14

# Install stoobly-agent
pipx install stoobly-agent

# Create local runtime scaffold
stoobly-agent scaffold app create my-app --runtime local
```

#### Q: How do local workflows work?

**A:** Local workflows run stoobly-agent directly on your machine, proxying requests to your services without containerization.

**Example:**

```bash
# Create local runtime app
stoobly-agent scaffold app create my-app --runtime local

# Create service
stoobly-agent scaffold service create my-service

# Start workflow (runs locally)
stoobly-agent scaffold workflow up test
```

#### Q: Can I use local runtime if my services are in Docker?

**A:** Yes, local runtime only affects how stoobly-agent runs. Your services can still run in Docker containers.

**Example:**

```bash
# Stoobly runs locally, services in Docker
stoobly-agent scaffold app create my-app --runtime local

# Add service that runs in Docker
stoobly-agent scaffold service create api \
  --hostname api.local \
  --upstream-hostname localhost \
  --upstream-port 8080

# Start your service in Docker
docker run -p 8080:8080 my-api-image

# Start stoobly workflow locally
stoobly-agent scaffold workflow up test
```

#### Q: How do I troubleshoot local runtime issues?

**A:** Check Python version, verify stoobly-agent installation, and review logs.

**Example:**

```bash
# Check Python version
python3 --version

# Verify stoobly-agent
stoobly-agent --version

# Check logs with verbose output
stoobly-agent scaffold workflow up test \
  --log-level debug
```

***

### Local Workflows

#### Q: How do I explicitly use local runtime for a workflow?

**A:** Use the `stoobly-agent scaffold workflow` commands directly.

**Example:**

```bash
# Local runtime via CLI
stoobly-agent scaffold workflow up record
stoobly-agent scaffold workflow up mock
stoobly-agent scaffold workflow up test
```

#### Q: How do I use local runtime?

**A:** Create the app with `--runtime local` (or use default) and use CLI commands for workflows.

**Example:**

```bash
# App created with local runtime (default)
stoobly-agent scaffold app create my-app
stoobly-agent scaffold service create my-service
```

***

### Local Migration

#### Q: How do I migrate from Docker to local runtime?

**A:** Recreate the app with local runtime and use CLI commands instead of Makefile.

**Example:**

```bash
# Currently using Docker
# Recreate with local runtime
stoobly-agent scaffold app create my-app --runtime local

# Now use local runtime commands
stoobly-agent scaffold service create my-service
```

***

### Getting Started with Local Runtime Commands

#### Q: How do I run workflow commands with local runtime?

**A:** Use `stoobly-agent scaffold workflow` commands directly. No Makefile is needed for local runtime.

**Example:**

```bash
# Start a workflow
stoobly-agent scaffold workflow up test

# Stop a workflow
stoobly-agent scaffold workflow down test
```

***

### Recording Workflow

#### Q: How do I start a recording workflow with local runtime?

**A:** Use `stoobly-agent scaffold workflow up record` to start the recording workflow, which sets up the proxy to capture HTTP requests. Use `stoobly-agent intercept enable` to enable intercept to start recording.

**Example:**

```bash
stoobly-agent scaffold workflow up record
stoobly-agent intercept enable
```

#### Q: How do I stop a recording workflow with local runtime?

**A:** Use `stoobly-agent scaffold workflow down record` to stop and clean up the recording workflow.

**Example:**

```bash
stoobly-agent scaffold workflow down record
```

#### Q: How do I view logs from the recording workflow with local runtime?

**A:** Use the scaffold log commands to see what requests were intercepted and the raw workflow process output.

**Example:**

```bash
# Show intercepted request logs (mock/record status, response codes)
stoobly-agent scaffold request logs list record

# Show raw workflow process output (startup errors, config issues)
stoobly-agent scaffold workflow logs record

# List all recorded requests
stoobly-agent request list
```

#### Q: How do I list services in the recording workflow with local runtime?

**A:** Use `stoobly-agent scaffold workflow services` to display all configured services.

**Example:**

```bash
stoobly-agent scaffold workflow services record
```

#### Q: How do I view the recorded requests report with local runtime?

**A:** Use `stoobly-agent request list` to display all intercepted and recorded requests.

**Example:**

```bash
stoobly-agent request list
```

***

### Mock Workflow

#### Q: How do I start a mock workflow with local runtime?

**A:** Use `stoobly-agent scaffold workflow up mock` to start the mock workflow, which serves mocked responses based on recorded data. Use `stoobly-agent intercept enable` to enable intercept to start mocking.

**Example:**

```bash
stoobly-agent scaffold workflow up mock
stoobly-agent intercept enable
```

#### Q: How do I stop a mock workflow with local runtime?

**A:** Use `stoobly-agent scaffold workflow down mock` to stop and clean up the mock workflow.

**Example:**

```bash
stoobly-agent scaffold workflow down mock
```

#### Q: How do I view logs from the mock workflow with local runtime?

**A:** Use the scaffold log commands to verify requests are being served from recordings and diagnose any mock failures.

**Example:**

```bash
# Show intercepted request logs (confirms whether responses are mocked or passed through)
stoobly-agent scaffold request logs list mock

# Show raw workflow process output (startup errors, config issues)
stoobly-agent scaffold workflow logs mock

# List all recorded requests
stoobly-agent request list
```

#### Q: How do I list services in the mock workflow with local runtime?

**A:** Use `stoobly-agent scaffold workflow services` to display all configured services.

**Example:**

```bash
stoobly-agent scaffold workflow services mock
```

#### Q: How do I view the mock requests report with local runtime?

**A:** Use `stoobly-agent request list` to display a list of all mocked requests.

**Example:**

```bash
stoobly-agent request list
```

***

### Test Workflow

#### Q: How do I start a test workflow with local runtime?

**A:** Use `stoobly-agent scaffold workflow up test` to start the test workflow, which runs automated tests against your services. Use `stoobly-agent intercept enable` to enable intercept to start testing.

**Example:**

```bash
stoobly-agent scaffold workflow up test
stoobly-agent intercept enable
```

#### Q: How do I stop a test workflow with local runtime?

**A:** Use `stoobly-agent scaffold workflow down test` to stop and clean up the test workflow.

**Example:**

```bash
stoobly-agent scaffold workflow down test
```

#### Q: How do I view logs from the test workflow with local runtime?

**A:** Use the scaffold log commands to see what requests were tested and their results.

**Example:**

```bash
# Show intercepted request logs (test results, response codes)
stoobly-agent scaffold request logs list test

# Show raw workflow process output (startup errors, config issues)
stoobly-agent scaffold workflow logs test

# List all test requests
stoobly-agent request list
```

#### Q: How do I list services in the test workflow with local runtime?

**A:** Use `stoobly-agent scaffold workflow services` to display all configured services.

**Example:**

```bash
stoobly-agent scaffold workflow services test
```

#### Q: How do I view the test requests report with local runtime?

**A:** Use `stoobly-agent request list` to display a list of all test requests and results.

**Example:**

```bash
stoobly-agent request list
```

***

### Scenario Management

#### Q: How do I create a scenario with local runtime?

**A:** Use `stoobly-agent scenario create` to create a new scenario.

**Example:**

```bash
stoobly-agent scenario create "User Login Flow"
```

#### Q: How do I list all scenarios with local runtime?

**A:** Use `stoobly-agent scenario list` to display all available scenarios.

**Example:**

```bash
stoobly-agent scenario list
```

#### Q: How do I delete a scenario with local runtime?

**A:** Use `stoobly-agent scenario delete` to delete a specific scenario.

**Example:**

```bash
stoobly-agent scenario delete <SCENARIO-KEY>
```

#### Q: How do I snapshot a scenario with local runtime?

**A:** Use `stoobly-agent scenario snapshot` to create committable files for a scenario.

**Example:**

```bash
stoobly-agent scenario snapshot <SCENARIO-KEY>
```

#### Q: How do I reset a scenario to its snapshot state with local runtime?

**A:** Use `stoobly-agent scenario reset` to restore a scenario from its snapshot.

**Example:**

```bash
stoobly-agent scenario reset <SCENARIO-KEY>
```

#### Q: How do I overwrite a scenario with local runtime?

**A:** Use `stoobly-agent scenario overwrite` to overwrite an existing scenario.

**Example:**

```bash
stoobly-agent scenario overwrite <SCENARIO-KEY>
```

***

### Certificate Management

#### Q: How do I install the CA certificate with local runtime?

**A:** Use `stoobly-agent ca-cert install` to install the CA certificate.

**Example:**

```bash
stoobly-agent ca-cert install
```

#### Q: How do I skip the CA certificate installation prompt with local runtime?

**A:** Set the `STOOBLY_CA_CERTS_INSTALL_CONFIRM` environment variable to `y` before running the workflow.

**Example:**

```bash
export STOOBLY_CA_CERTS_INSTALL_CONFIRM=y
stoobly-agent scaffold workflow up test
```

***

### Hostname Management

#### Q: How do I skip the hostname installation prompt with local runtime?

**A:** Set the `STOOBLY_HOSTNAME_INSTALL_CONFIRM` environment variable to `y` to automatically confirm hostname installation.

**Example:**

```bash
export STOOBLY_HOSTNAME_INSTALL_CONFIRM=y
stoobly-agent scaffold workflow up test
```

#### Q: How do I prevent hostname installation with local runtime?

**A:** Set the `STOOBLY_HOSTNAME_INSTALL_CONFIRM` environment variable to `n` to skip hostname installation.

**Example:**

```bash
export STOOBLY_HOSTNAME_INSTALL_CONFIRM=n
stoobly-agent scaffold workflow up mock
```

***

### Intercept Management

#### Q: How do I enable intercept mode with local runtime?

**A:** Use `stoobly-agent intercept enable` with an optional scenario key to enable request interception.

**Example:**

```bash
stoobly-agent intercept enable --scenario-key "<SCENARIO-KEY>"
```

#### Q: How do I disable intercept mode with local runtime?

**A:** Use `stoobly-agent intercept disable` to turn off request interception.

**Example:**

```bash
stoobly-agent intercept disable
```

***

### Environment Variables & Configuration

#### Q: How do I specify a custom application directory with local runtime?

**A:** Use the `--app-dir-path` option when running workflow commands.

**Example:**

```bash
stoobly-agent scaffold workflow up test --app-dir-path /path/to/my-app
```

#### Q: How do I use a custom .env file with workflows in local runtime?

**A:** Set the `STOOBLY_DOTENV_FILE` environment variable to specify your .env file path.

**Example:**

```bash
export STOOBLY_DOTENV_FILE=/path/to/custom.env
stoobly-agent scaffold workflow up mock
```

#### Q: How do I specify custom CA certificate directory with local runtime?

**A:** Use the `--ca-certs-dir-path` option when running workflow commands.

**Example:**

```bash
stoobly-agent scaffold workflow up test --ca-certs-dir-path /path/to/certs
```

#### Q: How do I pass additional service options to workflows with local runtime?

**A:** Use the `--service` option multiple times or pass options directly to the workflow command.

**Example:**

```bash
stoobly-agent scaffold workflow up test --service api --service database
```

#### Q: How do I specify a custom context directory with local runtime?

**A:** Use the `--context-dir-path` option when running workflow commands.

**Example:**

```bash
stoobly-agent scaffold workflow up test --context-dir-path /path/to/context
```

***

### Advanced Workflow Options

#### Q: How do I pass additional options to workflow up commands with local runtime?

**A:** Add options directly to the `stoobly-agent scaffold workflow up` command.

**Example:**

```bash
stoobly-agent scaffold workflow up test --detach
```

#### Q: How do I run a workflow with a custom namespace with local runtime?

**A:** Use the `--namespace` option to specify a custom workflow namespace.

**Note:** Namespaces are only supported by test workflows and custom workflows based on the test workflow template. Record and mock workflows do not support namespaces.

**Example:**

```bash
stoobly-agent scaffold workflow up test --namespace my-custom-namespace
```

#### Q: How do I filter services when starting a workflow with local runtime?

**A:** Use the `--service` option to specify which services to include.

**Example:**

```bash
stoobly-agent scaffold workflow up mock --service api --service frontend
```

***

### Combining Multiple Options

#### Q: How do I run a fully automated workflow without any prompts with local runtime?

**A:** Set both hostname and CA certificate confirmation environment variables before running the workflow.

**Example:**

```bash
export STOOBLY_HOSTNAME_INSTALL_CONFIRM=y
export STOOBLY_CA_CERTS_INSTALL_CONFIRM=y
stoobly-agent scaffold workflow up test
```

#### Q: How do I run a workflow with custom directories and environment with local runtime?

**A:** Use command-line options and environment variables together to customize all aspects of the workflow.

**Example:**

```bash
export STOOBLY_DOTENV_FILE=/path/to/.env.production
stoobly-agent scaffold workflow up mock \
  --app-dir-path /path/to/app \
  --service api
```

***

### Local Runtime Troubleshooting

#### Q: How do I check if stoobly-agent is installed?

**A:** Run `stoobly-agent --version` to verify installation.

**Example:**

```bash
stoobly-agent --version
```

#### Q: How do I verify Python version compatibility?

**A:** Run `python3 --version` to check if you have Python 3.12, 3.13, or 3.14.

**Example:**

```bash
python3 --version  # Should be 3.12, 3.13, or 3.14
```

#### Q: What do I do if pipx is not installed?

**A:** Install pipx using your system package manager or Python pip.

**Example:**

```bash
# On macOS
brew install pipx

# On Linux
python3 -m pip install --user pipx
python3 -m pipx ensurepath
```

#### Q: How do I view what services are configured with local runtime?

**A:** Use the workflow-specific services command to list all configured services.

**Example:**

```bash
stoobly-agent scaffold workflow services record
stoobly-agent scaffold workflow services mock
stoobly-agent scaffold workflow services test
```

#### Q: How do I validate my service configuration?

**A:** Use `scaffold service show` to view the current configuration.

**Example:**

```bash
stoobly-agent scaffold service show api
```

#### Q: What do I do if a workflow fails to start?

**A:** Check the logs for errors and verify service configurations.

**Example:**

```bash
# View logs
stoobly-agent scaffold workflow logs record

# Verify services
stoobly-agent scaffold service list
```

***

### Quick Reference

#### Q: What are the most common local runtime commands I'll use?

**A:** Here's a quick reference of the most frequently used commands:

**Example:**

```bash
# Start workflows (then enable intercept)
stoobly-agent scaffold workflow up record    # Start recording
stoobly-agent intercept enable

stoobly-agent scaffold workflow up mock      # Start mocking
stoobly-agent intercept enable

stoobly-agent scaffold workflow up test      # Start testing
stoobly-agent intercept enable

# Disable intercept
stoobly-agent intercept disable

# Stop workflows
stoobly-agent scaffold workflow down record
stoobly-agent scaffold workflow down mock
stoobly-agent scaffold workflow down test

# Manage scenarios
stoobly-agent scenario list
stoobly-agent scenario create "My Scenario"
stoobly-agent scenario snapshot <SCENARIO-KEY>

# View requests
stoobly-agent request list

# View logs (crucial for debugging and verifying mock/record behavior)
stoobly-agent scaffold request logs list record   # what was intercepted during record
stoobly-agent scaffold request logs list mock     # confirms responses served from recordings
stoobly-agent scaffold request logs list test     # test results per request
stoobly-agent scaffold workflow logs mock         # raw workflow process output
```

#### Q: How do I create an alias for easier command usage with local runtime?

**A:** Add an alias to your shell configuration file for convenience.

**Example:**

```bash
# Add to ~/.bashrc or ~/.zshrc
alias swf='stoobly-agent scaffold workflow'

# Then use it like:
swf up record
swf down mock
swf services test
```


# Scenario

## Stoobly Scenario CLI - Questions & Answers

The scenario CLI enables you to manage collections of related HTTP requests as scenarios. Scenarios help organize test flows, user journeys, and API workflows that involve multiple requests executed in sequence.

***

### Understanding Scenarios

#### Q: What is a scenario in Stoobly?

**A:** A scenario is a collection of related HTTP requests that represent a user flow, test case, or API workflow. Scenarios execute requests in sequence and can validate responses.

**Example:**

```bash
# Create a scenario for user login flow
stoobly-agent scenario create "User Login Flow"

# The scenario will contain multiple requests:
# 1. GET /api/csrf-token
# 2. POST /api/login
# 3. GET /api/user/profile
```

#### Q: Why should I use scenarios?

**A:** Scenarios help organize related requests, enable end-to-end testing, support workflow validation, and make it easy to share test cases with your team via version control.

**Example:**

```bash
# Instead of managing 10 individual requests
stoobly-agent request replay "<REQUEST-KEY-1>"
stoobly-agent request replay "<REQUEST-KEY-2>"
# ... (8 more)

# Use a scenario
stoobly-agent scenario replay user-checkout-flow
```

***

### Creating Scenarios

#### Q: How do I create a new scenario?

**A:** Use `scenario create` with a descriptive name for your scenario.

**Example:**

```bash
stoobly-agent scenario create "User Login Flow"
```

#### Q: How do I create a scenario with a description?

**A:** Use the `--description` option to add context to your scenario.

**Example:**

```bash
stoobly-agent scenario create "API Integration Test" --description "Tests all critical API endpoints for the mobile app"
```

#### Q: How do I create a scenario in a specific project?

**A:** Use the `--project-key` option to specify the project (remote features).

**Example:**

```bash
stoobly-agent scenario create "Payment Flow" --project-key "<PROJECT-KEY>"
```

#### Q: How do I format the output when creating a scenario?

**A:** Use the `--format` option to control how the created scenario is displayed.

**Example:**

```bash
# JSON format:
stoobly-agent scenario create "Checkout Flow" --format json

# Table format
stoobly-agent scenario create "User Registration" --format table

# CSV format
stoobly-agent scenario create "Admin Panel" --format csv
```

#### Q: How do I add requests to a scenario?

**A:** Record or replay requests with the `--scenario-key` option to add them to a scenario.

**Example:**

```bash
# First, create the scenario and note the key
stoobly-agent scenario create "User Login Flow"
# Output: Created scenario with key: <SCENARIO-KEY>

# Then record requests to that scenario
stoobly-agent record -X POST -d '{"username":"user","password":"pass"}' https://api.example.com/login --scenario-key "<SCENARIO-KEY>"

# Or replay and record to the scenario
stoobly-agent request replay "<REQUEST-KEY>" --record --scenario-key "<SCENARIO-KEY>"
```

***

### Listing Scenarios

#### Q: How do I view all scenarios?

**A:** Use `scenario list` to display all scenarios with pagination.

**Example:**

```bash
stoobly-agent scenario list
```

#### Q: How do I paginate through scenarios?

**A:** Use the `--page` and `--size` options to control pagination.

**Example:**

```bash
# Show first 10 scenarios (default)
stoobly-agent scenario list --page 0 --size 10

# Show next 20 scenarios
stoobly-agent scenario list --page 1 --size 20

# Show 50 scenarios per page
stoobly-agent scenario list --page 0 --size 50
```

#### Q: How do I search for specific scenarios?

**A:** Use the `--search` option to filter scenarios by name or description.

**Example:**

```bash
# Search by name
stoobly-agent scenario list --search "login"

# Search by description
stoobly-agent scenario list --search "payment"
```

#### Q: How do I sort scenarios?

**A:** Use `--sort-by` and `--sort-order` options to control sorting.

**Example:**

```bash
# Sort by creation date (newest first, default)
stoobly-agent scenario list --sort-by created_at --sort-order desc

# Sort by creation date (oldest first)
stoobly-agent scenario list --sort-by created_at --sort-order asc

# Sort by name alphabetically
stoobly-agent scenario list --sort-by name --sort-order asc
```

#### Q: How do I format the scenario list output?

**A:** Use the `--format` option to change output format.

**Example:**

```bash
# Table format (default)
stoobly-agent scenario list --format table

# JSON format
stoobly-agent scenario list --format json

# CSV format
stoobly-agent scenario list --format csv
```

#### Q: How do I select specific columns to display?

**A:** Use the `--select` option to choose which columns to show.

**Example:**

```bash
# Show only specific columns
stoobly-agent scenario list --select id --select name --select created_at

# Show key and name only
stoobly-agent scenario list --select key --select name --without-headers
```

***

### Viewing Scenario Details

#### Q: How do I view details about a specific scenario?

**A:** Use `scenario show` with the scenario key.

**Example:**

```bash
stoobly-agent scenario show "<SCENARIO-KEY>"
```

#### Q: How do I format scenario details output?

**A:** Use the `--format` option to control the display format.

**Example:**

```bash
# JSON format for scripting
stoobly-agent scenario show "<SCENARIO-KEY>" --format json

# Table format for readability
stoobly-agent scenario show "<SCENARIO-KEY>" --format table
```

#### Q: How do I get the request count for a scenario?

**A:** View scenario details or use the show command with specific column selection.

**Example:**

```bash
# Show all details including request count
stoobly-agent scenario show "<SCENARIO-KEY>"

# Select specific fields
stoobly-agent scenario show "<SCENARIO-KEY>" --select name --select request_count
```

***

### Replaying Scenarios

#### Q: How do I replay all requests in a scenario?

**A:** Use `scenario replay` with the scenario key to execute all requests in sequence.

**Example:**

```bash
stoobly-agent scenario replay "<SCENARIO-KEY>"
```

#### Q: How do I replay a scenario to a different host?

**A:** Use the `--host` option to override the request host for all requests.

**Example:**

```bash
# Replay to localhost
stoobly-agent scenario replay "<SCENARIO-KEY>" --host localhost:8080

# Replay to staging environment
stoobly-agent scenario replay "<SCENARIO-KEY>" --host staging.example.com
```

#### Q: How do I replay a scenario with a different scheme?

**A:** Use the `--scheme` option to change the protocol for all requests.

**Example:**

```bash
# Force HTTP
stoobly-agent scenario replay "<SCENARIO-KEY>" --scheme http

# Force HTTPS
stoobly-agent scenario replay "<SCENARIO-KEY>" --scheme https
```

#### Q: How do I update a scenario and by adding new responses?

**A:** Use the `--record` flag to capture the replayed responses.

**Example:**

```bash
stoobly-agent scenario replay "<SCENARIO-KEY>" --record
```

#### Q: How do I update a scenario and overwrite existing responses?

**A:** Use the `--overwrite` flag to replace stored responses (local mode only).

**Example:**

```bash
stoobly-agent scenario replay "<SCENARIO-KEY>" --overwrite
```

#### Q: How do I replay a scenario and save to history?

**A:** Use the `--save` flag to persist the replay session (local mode).

**Example:**

```bash
stoobly-agent scenario replay "<SCENARIO-KEY>" --save
```

#### Q: How do I replay a scenario with custom lifecycle hooks?

**A:** Use the `--lifecycle-hooks-path` option to apply custom processing.

**Example:**

```bash
stoobly-agent scenario replay "<SCENARIO-KEY>" --lifecycle-hooks-path ./hooks.py
```

#### Q: How do I increase logging verbosity when replaying?

**A:** Use the `--log-level` option to see more details.

**Example:**

```bash
# Debug level (most verbose)
stoobly-agent scenario replay "<SCENARIO-KEY>" --log-level debug

# Info level
stoobly-agent scenario replay "<SCENARIO-KEY>" --log-level info
```

#### Q: How do I format the replay response output?

**A:** Use the `--format` option to control response display.

**Example:**

```bash
# JSON format with full details
stoobly-agent scenario replay "<SCENARIO-KEY>" --format json
```

***

### Working with Aliases

#### Q: How do I replay a scenario with assigned alias values?

**A:** Use the `--assign` option to set alias values before replay.

**Example:**

```bash
# Assign single alias
stoobly-agent scenario replay "<SCENARIO-KEY>" --assign userId=12345

# Assign multiple aliases
stoobly-agent scenario replay "<SCENARIO-KEY>" --assign userId=12345 --assign token=abcde12345
```

#### Q: How do I validate alias values during scenario execution?

**A:** Use the `--validate` option to specify validation rules for aliases.

**Example:**

```bash
# Validate userId is an integer
stoobly-agent scenario replay "<SCENARIO-KEY>" --validate "userId=?int"

# Validate multiple aliases
stoobly-agent scenario replay "<SCENARIO-KEY>" --validate "userId=?int" --validate "email=?string"
```

#### Q: How do I control alias resolution strategy?

**A:** Use the `--alias-resolve-strategy` option to specify how aliases are resolved.

**Example:**

```bash
# No alias resolution (default)
stoobly-agent scenario replay "<SCENARIO-KEY>" --alias-resolve-strategy none

# First-in-first-out resolution
stoobly-agent scenario replay "<SCENARIO-KEY>" --alias-resolve-strategy fifo

# Last-in-first-out resolution
stoobly-agent scenario replay "<SCENARIO-KEY>" --alias-resolve-strategy lifo
```

#### Q: How do I repeat scenario execution for each alias value?

**A:** Use the `--group-by` option to iterate over alias values.

**Example:**

```bash
# Execute scenario once for each userId value
stoobly-agent scenario replay "<SCENARIO-KEY>" --group-by userId
```

#### Q: How do I use an existing trace for scenario execution?

**A:** Use the `--trace-id` option to leverage a previous trace.

**Example:**

```bash
stoobly-agent scenario replay "<SCENARIO-KEY>" --trace-id trace-<TRACE-ID>
```

***

### Snapshots and Version Control

#### Q: How do I create a snapshot of a scenario?

**A:** Use `scenario snapshot create` to create committable files for the scenario (local mode only).

**Example:**

```bash
stoobly-agent scenario snapshot create "<SCENARIO-KEY>"
```

#### Q: How do I delete a scenario snapshot?

**A:** Use the `--action delete` option with snapshot create command.

**Example:**

```bash
stoobly-agent scenario snapshot create "<SCENARIO-KEY>" --action delete
```

#### Q: How do I snapshot a scenario with decoded response bodies?

**A:** Use the `--decode` flag to decode response bodies in the snapshot.

**Example:**

```bash
stoobly-agent scenario snapshot create "<SCENARIO-KEY>" --decode
```

#### Q: How do I reset a scenario to its snapshot state?

**A:** Use `scenario snapshot reset` to restore a scenario from its snapshot. This reverts the scenario to the exact state from when the snapshot was created, discarding any changes.

{% hint style="warning" %}
This command **reverts** the scenario to the last committed snapshot. It does not merge new requests. If you need to incorporate new traffic, record or replay with `--scenario-key` instead of resetting.
{% endhint %}

**Example:**

```bash
stoobly-agent scenario snapshot reset "<SCENARIO-KEY>"
```

#### Q: What happens when I reset a scenario?

**A:** Reset will:

1. Restore the scenario metadata (name, description) from the snapshot
2. Restore all requests in the scenario to their snapshot states
3. Discard any modifications made since the snapshot was created
4. Return the scenario to an exact known state

**Example:**

```bash
# Before: Scenario has been modified with new requests
# After: Scenario matches the snapshot exactly

stoobly-agent scenario snapshot reset "<SCENARIO-KEY>"
```

#### Q: How do I check what will change before resetting?

**A:** Use `scenario snapshot diff` to preview all changes before applying reset.

**Example:**

```bash
# See what would change
stoobly-agent scenario snapshot diff "<SCENARIO-KEY>"

# See full raw HTTP diffs for each request
stoobly-agent scenario snapshot diff "<SCENARIO-KEY>" --full

# Review the output carefully

# If you want to proceed:
stoobly-agent scenario snapshot reset "<SCENARIO-KEY>"
```

#### Q: How do I force delete when resetting a scenario?

**A:** Use the `--force` flag to hard delete the scenario before resetting.

**Example:**

```bash
stoobly-agent scenario snapshot reset "<SCENARIO-KEY>" --force
```

#### Q: When should I reset a scenario vs. add new requests?

**A:**

* **Reset**: Use when you made unwanted changes and want to discard them
* **Add requests**: Use when you want to keep the snapshot and add new requests

**Example:**

```bash
# Scenario is in snapshot state
# Option 1: Add a new request (keeps snapshot requests)
stoobly-agent record https://api.example.com/new --scenario-key "<SCENARIO-KEY>"

# Option 2: Reset if you change your mind
stoobly-agent scenario snapshot reset "<SCENARIO-KEY>"
```

#### Q: Can I undo a reset?

**A:** No, reset is permanent. The changes are lost. To prevent accidental data loss:

1. Always check diff before resetting
2. Commit snapshots to Git before making changes
3. Use version control to restore previous snapshot states

**Example:**

```bash
# Best practice: Always check before reset
stoobly-agent scenario snapshot diff "<SCENARIO-KEY>"

# Commit snapshots to Git
git add .stoobly/snapshots/
git commit -m "Checkpoint before major changes"

# Now safe to experiment
# If you reset by mistake, can restore from Git
git restore .stoobly/snapshots/
stoobly-agent snapshot apply
```

#### Q: How do I share scenarios with my team via git?

**A:** Create snapshots and commit them to version control.

**Example:**

```bash
# Create snapshot
stoobly-agent scenario snapshot create "<SCENARIO-KEY>" --decode

# Commit to git
git add .stoobly/snapshots/scenarios/
git commit -m "Add user login scenario snapshot"
git push

# Team member pulls and uses
git pull
stoobly-agent snapshot apply # Apply snapshots to local database
```

#### Q: How do I see what changed in a scenario?

**A:** Use `scenario snapshot diff` to view differences between your current scenario and its last snapshot.

**Example:**

```bash
# Show what changed in the scenario
stoobly-agent scenario snapshot diff "<SCENARIO-KEY>"
```

#### Q: What does the scenario diff show?

**A:** The scenario diff displays:

* Changes to scenario metadata (name, description)
* Changes to requests in the scenario (added, removed, or modified)
* Response body changes for each request
* Headers and request properties that differ

**Example:**

```bash
# View detailed scenario changes
stoobly-agent scenario snapshot diff "<SCENARIO-KEY>"

# Show full raw HTTP request diffs for all scenario requests
stoobly-agent scenario snapshot diff "<SCENARIO-KEY>" --full
```

#### Q: How do I see diffs for all scenarios that have changed?

**A:** Run `scenario snapshot diff` without a scenario key to see all scenarios with changes.

**Example:**

```bash
# Show diffs for all scenarios
stoobly-agent scenario snapshot diff

# Show full raw diffs for all scenarios
stoobly-agent scenario snapshot diff --full
```

#### Q: When should I use diff?

**A:** Use diff to review changes before deciding whether to reset a scenario or commit changes to git. It helps prevent accidental loss of important modifications.

**Example:**

```bash
# Check changes before resetting
stoobly-agent scenario snapshot diff "<SCENARIO-KEY>"

# If happy with changes, commit:
stoobly-agent snapshot apply

# If want to discard changes:
stoobly-agent scenario snapshot reset "<SCENARIO-KEY>"
```

***

### Deleting Scenarios

#### Q: How do I delete a scenario?

**A:** Use `scenario delete` with the scenario key.

**Example:**

```bash
stoobly-agent scenario delete "<SCENARIO-KEY>"
```

#### Q: What happens to requests when I delete a scenario?

**A:** The scenario is deleted but the individual requests remain in storage unless explicitly deleted.

**Example:**

```bash
# Delete scenario (requests remain)
stoobly-agent scenario delete "<SCENARIO-KEY>"

# To also delete requests, delete them individually
stoobly-agent request delete "<REQUEST-KEY-1>"
stoobly-agent request delete "<REQUEST-KEY-2>"
```

***

### Scenario Workflows

#### Q: How do I create a complete user flow scenario?

**A:** Create the scenario, then record or add requests in the correct sequence.

**Example:**

```bash
# 1. Create scenario
stoobly-agent scenario create "Complete Checkout Flow"
# Output: Created scenario with key: <SCENARIO-KEY>

# 2. Record requests in sequence
stoobly-agent record https://api.example.com/cart --scenario-key "<SCENARIO-KEY>"
stoobly-agent record -X POST -d '{"items":[]}' https://api.example.com/cart/add --scenario-key "<SCENARIO-KEY>"
stoobly-agent record -X POST https://api.example.com/checkout --scenario-key "<SCENARIO-KEY>"
stoobly-agent record -X POST https://api.example.com/payment --scenario-key "<SCENARIO-KEY>"

# 3. Replay the complete flow
stoobly-agent scenario replay "<SCENARIO-KEY>"
```

#### Q: How do I update a scenario with new requests (add to the scenario)?

**A:** To update a scenario by **adding** requests (without overwriting existing ones), record or replay new requests while specifying the scenario key with the `--scenario-key` option. This appends new requests to the scenario.

**Option 1: Record a new request and add it to the scenario**

```bash
stoobly-agent record https://api.example.com/new-endpoint --scenario-key "<SCENARIO-KEY>"
```

**Option 2: Replay an existing request and add it to the scenario**

```bash
stoobly-agent request replay "<REQUEST-KEY>" --record --scenario-key "<SCENARIO-KEY>"
```

**Option 3: Add multiple new requests to a scenario**

```bash
# Record multiple endpoints and add them all to the same scenario
stoobly-agent record https://api.example.com/endpoint1 --scenario-key "<SCENARIO-KEY>"
stoobly-agent record https://api.example.com/endpoint2 --scenario-key "<SCENARIO-KEY>"
stoobly-agent record https://api.example.com/endpoint3 --scenario-key "<SCENARIO-KEY>"
```

#### Q: How do I update all requests in a scenario by overwriting responses when test cases exist?

**A:** When you have E2E test cases (e.g., Playwright or Cypress), use the Stoobly JavaScript client library to **re-record and overwrite** the scenario's stored responses by running your tests with recording enabled.

**Steps:**

1. Install the Stoobly JavaScript client library:

```bash
npm install stoobly --save-dev
```

2. Set up the interceptor in your tests following the [JavaScript Client Library](https://docs.stoobly.com/faq/scaffold/e2e-testing/js-client) setup instructions.
3. Run your tests with recording enabled by setting the `STOOBLY_RECORD` environment variable:

```bash
STOOBLY_RECORD=true npm test
```

This will re-record all API requests and responses captured during the test run, updating the scenario with the latest data.

More details: [JavaScript Client Library](https://docs.stoobly.com/faq/scaffold/e2e-testing/js-client), [How to Update Scenarios](https://docs.stoobly.com/guides/how-to-update-requests/how-to-update-scenarios/)

#### Q: How do I update all requests in a scenario by overwriting responses when test cases do not exist?

**A:** When you don't have test cases, use lifecycle hooks to add valid credentials and replay the scenario with the `--overwrite` flag. This **overwrites all stored responses** in the scenario with new ones from the live API.

**Steps:**

1. Create a `lifecycle_hooks.py` script to add valid credentials (e.g., an `Authorization` header):

```python
from stoobly_agent.app.proxy.replay.context import ReplayContext

def handle_before_replay(context: ReplayContext):
    flow = context.flow
    request = flow.request
    request.headers['Authorization'] = 'Bearer <TOKEN>'
```

2. Replay the scenario with overwrite enabled:

```bash
stoobly-agent scenario replay --overwrite "<SCENARIO-KEY>" --lifecycle-hooks-path ./lifecycle_hooks.py
```

This replays all requests in the scenario against the live API and overwrites the stored responses with the new ones.

More details: [Updating with Replay](https://docs.stoobly.com/guides/how-to-update-requests/how-to-update-scenarios/updating-with-replay), [Lifecycle Hooks](https://docs.stoobly.com/core-concepts/agent/lifecycle-hooks)

#### Q: How do I test multiple scenarios in sequence?

**A:** Use a script to test scenarios one after another.

**Example:**

```bash
#!/bin/bash
# Replay multiple scenarios

scenarios=("login-flow" "checkout-flow" "admin-panel")

for scenario in "${scenarios[@]}"; do
  echo "Replaying scenario: $scenario"
  if ! stoobly-agent scenario replay $scenario; then
    echo "Failed: $scenario"
    exit 1
  fi
done

echo "All scenarios completed!"
```

***

### Advanced Scenario Operations

#### Q: How do I chain multiple scenarios?

**A:** Use a script to execute scenarios in sequence with dependency handling.

**Example:**

```bash
#!/bin/bash
# Chain scenarios with dependencies

# Setup scenario
stoobly-agent scenario replay setup-data --save
if [ $? -ne 0 ]; then
  echo "Setup failed"
  exit 1
fi

# Main scenario
stoobly-agent scenario replay main-flow --save
if [ $? -ne 0 ]; then
  echo "Main flow failed"
  exit 1
fi

# Cleanup scenario
stoobly-agent scenario replay cleanup --save

echo "All scenarios completed"
```

#### Q: How do I extract data from one scenario to use in another?

**A:** Use aliases and traces to pass data between scenarios.

**Example:**

```bash
# First scenario creates data and assigns aliases
stoobly-agent scenario replay create-user \
  --save \
  --trace-id shared-trace \
  --assign email=user@example.com

# Second scenario uses the trace and aliases
stoobly-agent scenario replay login-user \
  --trace-id shared-trace \
  --assign email=user@example.com
```

***

### Monitoring and Debugging

#### Q: How do I debug a failing scenario?

**A:** Increase log level and use verbose output.

**Example:**

```bash
# Debug with verbose logging
stoobly-agent scenario replay "<SCENARIO-KEY>" --log-level debug

# Replay with logging to see each request
stoobly-agent scenario replay "<SCENARIO-KEY>" --log-level info
```

#### Q: How do I identify which request in a scenario is failing?

**A:** Use detailed output and logging to track request execution.

**Example:**

```bash
# Replay with detailed logging
stoobly-agent scenario replay "<SCENARIO-KEY>" --log-level info

# This shows each request as it executes
```

***

### Quick Reference

#### Q: What are the most common scenario commands?

**A:** Here's a quick reference of frequently used commands:

**Example:**

```bash
# Create scenarios
stoobly-agent scenario create "My Scenario"
stoobly-agent scenario create "API Flow" --description "Tests API endpoints"

# List scenarios
stoobly-agent scenario list
stoobly-agent scenario list --search "login"
stoobly-agent scenario list --format json

# View scenario details
stoobly-agent scenario show "<SCENARIO-KEY>"

# Replay scenarios
stoobly-agent scenario replay "<SCENARIO-KEY>"
stoobly-agent scenario replay "<SCENARIO-KEY>" --host staging.example.com
stoobly-agent scenario replay "<SCENARIO-KEY>" --record

# Snapshots
stoobly-agent scenario snapshot create "<SCENARIO-KEY>"
stoobly-agent scenario snapshot create "<SCENARIO-KEY>" --decode
stoobly-agent scenario snapshot reset "<SCENARIO-KEY>"

# Delete scenarios
stoobly-agent scenario delete "<SCENARIO-KEY>"
```

***

### Best Practices

#### Q: How should I organize my scenarios?

**A:** Group related requests by user flow, feature area, or test type.

**Example:**

```bash
# By user flow
stoobly-agent scenario create "User Registration Flow"
stoobly-agent scenario create "User Login Flow"
stoobly-agent scenario create "User Profile Update Flow"

# By feature area
stoobly-agent scenario create "Shopping Cart - Add Items"
stoobly-agent scenario create "Shopping Cart - Checkout"
stoobly-agent scenario create "Shopping Cart - Order History"

# By test type
stoobly-agent scenario create "Smoke Tests"
stoobly-agent scenario create "Integration Tests"
stoobly-agent scenario create "E2E Tests"
```

#### Q: How often should I snapshot scenarios?

**A:** Snapshot after significant changes or before releases.

**Example:**

```bash
# After adding new requests
stoobly-agent scenario snapshot create "<SCENARIO-KEY>" --decode
git add .stoobly/snapshots/
git commit -m "Update scenario with new endpoints"

# Before release
./snapshot-all-scenarios.sh
git tag -a v1.2.0 -m "Release 1.2.0 with scenario snapshots"
git push --tags
```

#### Q: What's the recommended workflow for scenario management?

**A:** Create → Record → Snapshot → Replay → Update cycle.

**Example:**

```bash
# 1. Create scenario
stoobly-agent scenario create "Payment Flow"

# 2. Record requests
stoobly-agent record "<URL-1>" --scenario-key "<SCENARIO-KEY>"

# 3. Snapshot for version control
stoobly-agent scenario snapshot create "<SCENARIO-KEY>" --decode
git add .stoobly/snapshots/ && git commit -m "Add payment flow"

# 4. Replay regularly
stoobly-agent scenario replay "<SCENARIO-KEY>"

# 5. Update when needed
stoobly-agent record "<URL-2>" --scenario-key "<SCENARIO-KEY>"
stoobly-agent scenario snapshot create "<SCENARIO-KEY>" --decode
git commit -am "Update payment flow with new endpoints"
```


# Snapshot

## Stoobly Snapshot CLI - Questions & Answers

The snapshot CLI manages version-controlled snapshots of requests and scenarios. Snapshots create committable files that enable team collaboration, historical tracking, and reproducible testing through version control systems like Git.

***

### Understanding Snapshots

#### Q: What are snapshots in Stoobly?

**A:** Snapshots are version-controlled, file-based representations of requests and scenarios that can be committed to Git. They enable team collaboration and historical tracking of API tests.

**Example:**

```bash
# Create snapshot of a request
stoobly-agent request snapshot create "<REQUEST-KEY>"

# Create snapshot of a scenario
stoobly-agent scenario snapshot create "<SCENARIO-KEY>"

# Snapshots are stored in .stoobly/snapshots/
ls .stoobly/snapshots/requests/
ls .stoobly/snapshots/scenarios/
```

#### Q: Why should I use snapshots?

**A:** Snapshots enable version control of your tests, team collaboration through Git, reproducible testing across environments, and historical tracking of API changes.

**Example:**

```bash
# Create snapshots
stoobly-agent scenario snapshot create user-login

# Commit to Git
git add .stoobly/snapshots/
git commit -m "Add user login test scenario"
git push

# Team members get the tests
git pull
stoobly-agent snapshot apply  # Apply all snapshots
```

#### Q: What's the difference between requests in the database and snapshots?

**A:** Database requests are local and ephemeral, while snapshots are file-based, version-controlled, and shareable across the team.

**Example:**

```bash
# Database: Local only
stoobly-agent request list  # Shows local requests

# Snapshots: Shareable via Git
stoobly-agent snapshot list  # Shows version-controlled snapshots
git add .stoobly/snapshots/ && git commit -m "Share tests"
```

***

### Listing Snapshots

#### Q: How do I view all snapshots?

**A:** Use resource-specific list commands to display snapshots. List request snapshots with `request snapshot list` or scenario snapshots with `scenario snapshot list`.

**Example:**

```bash
# List all request snapshots
stoobly-agent request snapshot list

# List all scenario snapshots
stoobly-agent scenario snapshot list
```

#### Q: How do I list only request snapshots?

**A:** Use `request snapshot list` to display all request snapshots.

**Example:**

```bash
# List request snapshots
stoobly-agent request snapshot list

# Show more results
stoobly-agent request snapshot list --size 50
```

#### Q: How do I list only scenario snapshots?

**A:** Use `scenario snapshot list` to display all scenario snapshots.

**Example:**

```bash
stoobly-agent scenario snapshot list
```

#### Q: How do I search for specific snapshots?

**A:** Use the `--search` option with a regex pattern to filter snapshots. The search behavior depends on the resource type:

* **For request snapshots** (using `request snapshot list`): The regex matches from the start of the URL or the start of the path. For example, `docs.stoobly.com` will not match `https://docs.stoobly.com` because the search starts from the beginning of the URL. Use `https://docs.stoobly.com` or `.*?docs.stoobly.com` to match URLs containing the domain.
* **For scenario snapshots** (using `scenario snapshot list`): The regex matches from the start of the scenario name or the start of the scenario description.

**Example:**

```bash
# Search request snapshots by URL path (matches from start of path)
stoobly-agent request snapshot list --search "/api/users"

# Search request snapshots by domain (use .*? to match anywhere in URL)
stoobly-agent request snapshot list --search ".*?example.com"

# Search request snapshots with regex (matches paths starting with /api/ and containing login)
stoobly-agent request snapshot list --search "^/api/.*login"

# Search scenario names/descriptions (matches from start)
stoobly-agent scenario snapshot list --search "^User.*"
```

#### Q: How do I filter snapshots by scenario key?

**A:** Use the `--scenario-key` option with `request snapshot list` to filter request snapshots that belong to a specific scenario.

**Example:**

```bash
# Filter request snapshots by scenario key
stoobly-agent request snapshot list --scenario-key "<SCENARIO-KEY>"

# Filter with regex pattern
stoobly-agent request snapshot list --scenario-key "^Login.*"
```

#### Q: How do I list pending (unprocessed) snapshots?

**A:** Use the `--pending` flag with resource-specific list commands to show snapshots that haven't been applied yet.

**Example:**

```bash
# List pending request snapshots
stoobly-agent request snapshot list --pending

# List pending scenario snapshots
stoobly-agent scenario snapshot list --pending
```

#### Q: How do I limit the number of snapshots displayed?

**A:** Use the `--size` option with resource-specific list commands to control the number of results.

**Example:**

```bash
# Show 20 request snapshots
stoobly-agent request snapshot list --size 20

# Show 50 scenario snapshots
stoobly-agent scenario snapshot list --size 50
```

#### Q: How do I format snapshot list output?

**A:** Use the `--format` option with resource-specific list commands to change output format.

**Example:**

```bash
# Table format (default)
stoobly-agent request snapshot list --format table

# JSON format
stoobly-agent request snapshot list --format json

# CSV format
stoobly-agent scenario snapshot list --format csv
```

#### Q: How do I select specific columns to display?

**A:** Use the `--select` option with resource-specific list commands to choose which columns to show.

**Example:**

```bash
# Show specific columns
stoobly-agent request snapshot list --select uuid --select path --select method

# Minimal output
stoobly-agent request snapshot list --select uuid --select snapshot --without-headers
```

***

### Applying Snapshots

#### Q: How do I apply all snapshots?

**A:** Use `snapshot apply` without arguments to apply all available snapshots.

**Example:**

```bash
# Apply all snapshots from .stoobly/snapshots/
stoobly-agent snapshot apply
```

#### Q: How do I apply a specific snapshot?

**A:** Use `snapshot apply` with the snapshot UUID.

**Example:**

```bash
# Get UUID from list
stoobly-agent snapshot list

# Apply specific snapshot
stoobly-agent snapshot apply "<SNAPSHOT-UUID>"
```

#### Q: What happens when I apply a snapshot?

**A:** Applying a snapshot creates or updates the corresponding request or scenario in your local database from the snapshot file.

**Example:**

```bash
# Team member gets snapshots from git
git pull

# Apply snapshots to local database
stoobly-agent snapshot apply

# Now can replay/test the requests
stoobly-agent scenario replay user-login
```

#### Q: How do I force apply snapshots with hard delete?

**A:** Use the `--force` flag to hard delete existing resources when applying.

**Example:**

```bash
# Force apply all snapshots
stoobly-agent snapshot apply --force

# Force apply specific snapshot
stoobly-agent snapshot apply "<SNAPSHOT-UUID>" --force
```

#### Q: What's the difference between apply and reset?

**A:** These commands serve different purposes:

* **`snapshot apply`**: Creates or updates requests/scenarios in your database **from snapshot files**. Use this when you have snapshot files (e.g., after pulling from git) and want to build your database from them. This is a bulk operation that processes snapshot files.
* **`request reset` or `scenario reset`**: Reverts a specific request or scenario that **already exists in your database** back to its snapshot state. Use this when you've made changes to a request/scenario and want to undo those changes by restoring from its snapshot.

**Example:**

```bash
# Apply all snapshots (build database from snapshot files)
# Use this after pulling snapshots from git or when setting up a new environment
stoobly-agent snapshot apply

# Reset specific request (revert changes to an existing request)
# Use this when you want to undo changes to a request you've modified
stoobly-agent request reset "<REQUEST-KEY>"

# Reset specific scenario (revert changes to an existing scenario)
# Use this when you want to undo changes to a scenario you've modified
stoobly-agent scenario reset "<SCENARIO-KEY>"
```

***

### Updating Snapshots

#### Q: How do I create/update a request snapshot?

**A:** Use `request snapshot create` with the request key to create or update a request snapshot.

**Example:**

```bash
# Create or update a request snapshot
stoobly-agent request snapshot create "<REQUEST-KEY>"

# Create snapshot with decoded response bodies
stoobly-agent request snapshot create "<REQUEST-KEY>" --decode
```

#### Q: How do I create/update a scenario snapshot?

**A:** Use `scenario snapshot create` with the scenario key to create or update a scenario snapshot.

**Example:**

```bash
# Create or update a scenario snapshot
stoobly-agent scenario snapshot create "<SCENARIO-KEY>"

# Create snapshot with decoded response bodies
stoobly-agent scenario snapshot create "<SCENARIO-KEY>" --decode
```

#### Q: How do I update a snapshot without verification?

**A:** Use the `--no-verify` flag to skip request verification.

**Example:**

```bash
stoobly-agent request snapshot create "<REQUEST-KEY>" --no-verify
stoobly-agent scenario snapshot create "<SCENARIO-KEY>" --no-verify
```

#### Q: What does snapshot verification do?

**A:** Verification ensures the raw HTTP request format is valid and fixes any formatting issues before creating the snapshot.

**Example:**

```bash
# With verification (default) - fixes malformed requests
stoobly-agent request snapshot create "<REQUEST-KEY>"

# Without verification - takes request as-is
stoobly-agent request snapshot create "<REQUEST-KEY>" --no-verify
```

***

### Resetting Snapshots

#### Q: How do I reset a request to its snapshot state?

**A:** Use `request snapshot reset` with the request key to revert a request back to its last snapshot state. This will discard any changes made to the request since the snapshot was created.

**Example:**

```bash
stoobly-agent request snapshot reset "<REQUEST-KEY>"
```

#### Q: What happens when I reset a request?

**A:** Reset will:

1. Load the request data from the last snapshot file
2. Overwrite the current request in your local database with snapshot data
3. Restore the exact request state from when the snapshot was created
4. Discard all changes made since the snapshot was created

**Example:**

```bash
# Before reset: Request has modifications
# After reset: Request matches snapshot state exactly

stoobly-agent request snapshot reset "<REQUEST-KEY>"
```

#### Q: How do I know what will be lost when I reset?

**A:** Use `request snapshot diff` to preview changes before resetting.

**Example:**

```bash
# See what will be lost
stoobly-agent request snapshot diff "<REQUEST-KEY>"

# Review the diff output carefully

# If you want to proceed with reset:
stoobly-agent request snapshot reset "<REQUEST-KEY>"
```

#### Q: How do I reset a request with force delete?

**A:** Use the `--force` flag to hard delete the request before restoring it from snapshot. This is useful if the request is in a corrupted state.

**Example:**

```bash
# Hard delete and restore from snapshot
stoobly-agent request snapshot reset "<REQUEST-KEY>" --force
```

#### Q: What's the difference between reset with and without --force?

**A:**

* **Without `--force`**: Updates the existing request with snapshot data. Safer option that preserves record history.
* **With `--force`**: Hard deletes the request completely, then recreates it from snapshot. Use this if the request is corrupted or if you want a clean state.

**Example:**

```bash
# Normal reset: Updates existing request
stoobly-agent request snapshot reset "<REQUEST-KEY>"

# Force reset: Delete and recreate from snapshot
stoobly-agent request snapshot reset "<REQUEST-KEY>" --force
```

#### Q: Can I undo a reset?

**A:** No, reset is permanent. Once a reset is applied, the changes are lost. However, you can:

1. Use `request snapshot diff` before resetting to understand what will change
2. Check Git history if you have snapshots committed
3. Use your database backups if available

**Example:**

```bash
# Always check diff before resetting
stoobly-agent request snapshot diff "<REQUEST-KEY>"

# If you made a mistake, check if there's a Git history
git log .stoobly/snapshots/

# Or restore from backup if available
```

#### Q: How do I reset a scenario to its snapshot state?

**A:** Use `scenario snapshot reset` with the scenario key to revert a scenario back to its last snapshot state.

**Example:**

```bash
stoobly-agent scenario snapshot reset "<SCENARIO-KEY>"
```

#### Q: What happens when I reset a scenario?

**A:** Reset will:

1. Load the scenario metadata from the last snapshot file
2. Update the scenario name and description from the snapshot
3. Restore all requests in the scenario to their snapshot states
4. Discard all changes made to the scenario and its requests since the snapshot

**Example:**

```bash
# Before reset: Scenario has modifications
# After reset: Scenario and all its requests match snapshot state

stoobly-agent scenario snapshot reset "<SCENARIO-KEY>"
```

#### Q: How do I know what will be lost when I reset a scenario?

**A:** Use `scenario snapshot diff` to preview all changes before resetting.

**Example:**

```bash
# See what will change in the scenario
stoobly-agent scenario snapshot diff "<SCENARIO-KEY>"

# See full raw HTTP diffs for all requests
stoobly-agent scenario snapshot diff "<SCENARIO-KEY>" --full

# Review carefully, then reset if needed
stoobly-agent scenario snapshot reset "<SCENARIO-KEY>"
```

#### Q: How do I reset a scenario with force delete?

**A:** Use the `--force` flag to hard delete the scenario before restoring it from snapshot.

**Example:**

```bash
# Hard delete scenario and restore from snapshot
stoobly-agent scenario snapshot reset "<SCENARIO-KEY>" --force
```

#### Q: When should I use reset?

**A:** Reset is useful when:

* You made accidental changes to requests or scenarios
* You want to undo modifications and return to a known good state
* You want to sync with the committed snapshot in Git
* You need to verify that the snapshot is still valid
* The scenario got corrupted and needs a clean restore

**Example Workflow:**

```bash
# Make changes to scenario
stoobly-agent record https://api.example.com/new-endpoint --scenario-key "<SCENARIO-KEY>"

# Realize the changes aren't needed
stoobly-agent scenario snapshot diff "<SCENARIO-KEY>"

# Check what changed, decide it's not needed

# Reset to last snapshot
stoobly-agent scenario snapshot reset "<SCENARIO-KEY>"

# Scenario is back to snapshot state
```

#### Q: Can I reset multiple requests or scenarios at once?

**A:** Use a script to reset multiple resources.

**Example:**

```bash
#!/bin/bash
# Reset all requests in a scenario

# List all request snapshots and reset each
stoobly-agent request snapshot list --format json | jq -r '.[].key' | while read key; do
  echo "Resetting request: $key"
  stoobly-agent request snapshot reset "$key"
done

# Reset all scenarios
stoobly-agent scenario snapshot list --format json | jq -r '.[].key' | while read key; do
  echo "Resetting scenario: $key"
  stoobly-agent scenario snapshot reset "$key"
done
```

#### Q: What's the difference between reset and apply?

**A:**

* **`reset`**: Reverts a specific resource (request or scenario) back to its snapshot state. Works on individual resources you've already modified.
* **`apply`**: Applies snapshots from snapshot files to create or update resources in your database. Works on unprocessed snapshots (typically after pulling from Git).

**Example:**

```bash
# Use apply when you pull snapshots from Git
git pull
stoobly-agent snapshot apply  # Creates/updates resources from snapshot files

# Use reset when you've modified a resource and want to undo
stoobly-agent request snapshot reset "<REQUEST-KEY>"  # Discard changes

# Use diff to understand the difference
stoobly-agent request snapshot diff "<REQUEST-KEY>"
```

***

### Global Snapshot Reset

#### Q: How do I reset all requests and scenarios to their snapshot states at once?

**A:** Use `snapshot reset` (without a resource key) to reset all requests and scenarios that have snapshots back to their last snapshot state. This is useful when you've made many changes and want to reset everything.

**Example:**

```bash
# Reset all requests and scenarios to snapshot states
stoobly-agent snapshot reset

# Will prompt for confirmation showing count of items to reset
# This will reset 5 request(s) and 3 scenario(s) to their last snapshot state (8 total). Continue?
```

#### Q: What happens when I run snapshot reset?

**A:** The command will:

1. Count all requests and scenarios that have snapshots
2. Ask for confirmation (unless `--yes` is used)
3. Reset each resource to its snapshot state
4. Report success/failure count for the operation

**Example:**

```bash
stoobly-agent snapshot reset
# Output:
# This will reset 5 request(s) and 3 scenario(s) to their last snapshot state (8 total).
# WARNING: --hard is set and will delete ALL requests and scenarios before resetting.
# Continue? [y/N]: y
# Successfully reset the request!
# Successfully reset the request!
# ... (more items)
```

#### Q: How do I skip the confirmation prompt?

**A:** Use the `--yes` flag to proceed without confirmation. Useful for automated scripts.

**Example:**

```bash
# Skip confirmation and reset all immediately
stoobly-agent snapshot reset --yes
```

#### Q: What's the --hard option for snapshot reset?

**A:** The `--hard` flag deletes ALL requests and scenarios in your database before resetting them from snapshots. This is a destructive operation that should be used carefully.

**Important:** `--hard` will delete:

* All requests not in snapshots
* All scenarios not in snapshots
* All requests in snapshots (they'll be recreated)
* All scenarios in snapshots (they'll be recreated)

**Example:**

```bash
# Hard reset: delete everything, then restore from snapshots
stoobly-agent snapshot reset --hard

# This will show a warning before proceeding:
# This will reset 5 request(s) and 3 scenario(s) to their last snapshot state (8 total).
# WARNING: --hard is set and will delete ALL requests and scenarios before resetting.
# Continue? [y/N]:
```

#### Q: When should I use --hard?

**A:** Use `--hard` in these situations:

* **Clean slate needed**: You want to remove all local changes and start fresh from snapshots
* **Database corruption**: Your database has inconsistent or corrupted data
* **Fresh environment setup**: Setting up a new environment from snapshots
* **Testing snapshot integrity**: Verify that all snapshots can be applied cleanly
* **Cleanup**: Remove clutter and unwanted requests/scenarios not in snapshots

**Example Workflows:**

```bash
# Workflow 1: Clean environment from Git
git clone <repo>
cd <repo>
stoobly-agent snapshot reset --hard --yes
# Result: Database contains only snapshot-defined requests/scenarios

# Workflow 2: Recover from corruption
stoobly-agent snapshot reset --hard
# All data reset from snapshots

# Workflow 3: Test snapshot integrity
stoobly-agent snapshot reset --hard --yes
stoobly-agent snapshot list  # Verify all snapshots present
```

#### Q: What's the difference between --hard and normal reset?

**A:**

| Aspect                    | Normal Reset | With --hard          |
| ------------------------- | ------------ | -------------------- |
| Deletes unsnapshot items? | No           | Yes                  |
| Deletes snapshot items?   | No           | Yes (recreates them) |
| Safe for normal use?      | Yes          | No (destructive)     |
| Data loss risk?           | Low          | High                 |
| Best for?                 | Undo changes | Fresh start          |

**Example:**

```bash
# Setup:
# Database has: request-a (snapshot), request-b (no snapshot)

# Normal reset:
stoobly-agent snapshot reset
# Result: request-a reset to snapshot, request-b unchanged

# With --hard:
stoobly-agent snapshot reset --hard
# Result: request-a deleted and recreated, request-b deleted
```

#### Q: What should I do before using --hard?

**A:** Before using `--hard`, take these safety measures:

1. Backup your database
2. Review what will be deleted with `snapshot list`
3. Commit snapshots to Git
4. Consider the impact on your team

**Example Safety Workflow:**

```bash
# Step 1: Check what will change
stoobly-agent request snapshot list
stoobly-agent scenario snapshot list

# Step 2: Backup database
cp -r .stoobly/db .stoobly/db.backup.$(date +%s)

# Step 3: Commit snapshots to Git
git add .stoobly/snapshots/
git commit -m "Backup before hard reset"
git push

# Step 4: Run with caution
stoobly-agent snapshot reset --hard --yes
```

#### Q: Can I undo a hard reset?

**A:** Hard reset is permanent. To recover:

1. **Restore from backup**: If you created a database backup
2. **Restore from Git**: If you committed snapshots before the reset
3. **Re-record data**: If you have the original traffic

**Example Recovery:**

```bash
# Option 1: Restore database backup
rm -rf .stoobly/db
cp -r .stoobly/db.backup.1234567 .stoobly/db

# Option 2: Restore from Git (if you committed before reset)
git log --oneline .stoobly/snapshots/
git checkout <commit-hash> -- .stoobly/snapshots/
stoobly-agent snapshot apply

# Option 3: Re-record from traffic
# Re-run your application with recording enabled
stoobly-agent run --intercept --intercept-mode record &
# Run your tests/app
# Stop and record new snapshots
```

#### Q: How does --lock-timeout work?

**A:** The `--lock-timeout` option prevents concurrent reset operations that could corrupt your database. Only one reset can run at a time within the specified timeout.

**Example:**

```bash
# Default timeout is 60 seconds
stoobly-agent snapshot reset

# Custom timeout (wait up to 120 seconds for another reset to finish)
stoobly-agent snapshot reset --lock-timeout 120

# If another reset is already running and timeout expires:
# Error: Another snapshot reset command is already running. Please wait for it to complete.
```

#### Q: Can I reset while other processes are running?

**A:** The lock mechanism ensures only one `snapshot reset` can run at a time. However, it's best practice to:

1. Stop your application
2. Stop the Stoobly agent if running
3. Run the reset
4. Restart applications

**Example Safe Reset:**

```bash
# Stop running processes
stoobly-agent stop  # if running

# Perform reset
stoobly-agent snapshot reset --hard --yes

# Verify everything is correct
stoobly-agent snapshot list
stoobly-agent request list

# Restart
stoobly-agent run --intercept
```

#### Q: How do I use snapshot reset in scripts or CI/CD?

**A:** Use the `--yes` flag to skip confirmation, and check exit codes to handle errors.

**Example Bash Script:**

```bash
#!/bin/bash
set -e  # Exit on error

echo "Resetting all snapshots..."
stoobly-agent snapshot reset --yes

if [ $? -eq 0 ]; then
  echo "Reset successful"
  stoobly-agent snapshot list
else
  echo "Reset failed" >&2
  exit 1
fi
```

**Example GitHub Actions:**

```yaml
- name: Reset snapshots
  run: stoobly-agent snapshot reset --hard --yes
  continue-on-error: true  # Optional: continue if reset fails

- name: Verify snapshots
  run: stoobly-agent request snapshot list
```

#### Q: What error messages might I see?

**A:** Common error messages and what they mean:

* **"Another snapshot reset command is already running"**: Wait for the other reset to complete
* **"Completed with X failures (Y succeeded)"**: Some resources failed to reset; check error logs
* **"Aborted."**: You rejected the confirmation prompt

**Example Troubleshooting:**

```bash
# If getting lock timeout error
# Check if another reset is running
ps aux | grep snapshot

# Kill stuck process if needed (use with caution)
pkill -f "snapshot reset"

# Try again
stoobly-agent snapshot reset --yes
```

#### Q: What counts as a "snapshot" for the reset operation?

**A:** Snapshots are counted from the snapshot log. Only requests and scenarios with PUT\_ACTION events in the snapshot log are included.

**Example:**

```bash
# To see what will be reset:
stoobly-agent request snapshot list
stoobly-agent scenario snapshot list

# These define what "snapshot reset" will operate on
```

***

### Comparing Snapshots

#### Q: How do I see the diff between a request and its snapshot?

**A:** Use `request snapshot diff` to show differences between the current request stored in your database and its last snapshot state.

**Example:**

```bash
# Show diff for a specific request
stoobly-agent request snapshot diff "<REQUEST-KEY>"
```

#### Q: What information does the diff show for a request?

**A:** The diff displays:

* Current request data from your local database
* Snapshot request data from the last saved version
* Detailed comparison of request properties (URL, method, headers, body)
* Response body comparisons

**Example:**

```bash
# See what changed in a request
stoobly-agent request snapshot diff "<REQUEST-KEY>"
# Output shows: added/removed/modified fields in headers, body, or response
```

#### Q: How do I see the full raw diff for all requests?

**A:** Use the `--full` flag to display the complete raw HTTP request diff for a specific request.

**Example:**

```bash
# Show full raw HTTP request diff
stoobly-agent request snapshot diff "<REQUEST-KEY>" --full

# Show raw diff for all requests with diffs
stoobly-agent request snapshot diff --full
```

#### Q: What does the --full flag show?

**A:** The `--full` flag displays the complete raw HTTP request format, showing exactly how the request has changed at the HTTP level.

**Example:**

```bash
# Without --full (summary view)
stoobly-agent request snapshot diff "<REQUEST-KEY>"
# Output: Shows parsed fields like method, path, headers, body

# With --full (raw HTTP view)
stoobly-agent request snapshot diff "<REQUEST-KEY>" --full
# Output: Shows full raw HTTP request format with all changes highlighted
```

#### Q: How do I see diffs for all requests that have changed?

**A:** Run `request snapshot diff` without specifying a request key to see diffs for all requests with snapshots.

**Example:**

```bash
# Show diffs for all requests with changes
stoobly-agent request snapshot diff

# Show full raw diffs for all requests
stoobly-agent request snapshot diff --full
```

#### Q: How do I see the diff between a scenario and its snapshot?

**A:** Use `scenario snapshot diff` to show differences between the current scenario stored in your database and its last snapshot state.

**Example:**

```bash
# Show diff for a specific scenario
stoobly-agent scenario snapshot diff "<SCENARIO-KEY>"
```

#### Q: What information does the scenario diff show?

**A:** The scenario diff displays:

* Scenario metadata changes (name, description)
* Request changes within the scenario
* For each request: added/removed/modified properties
* Overall scenario composition differences

**Example:**

```bash
# See what changed in a scenario
stoobly-agent scenario snapshot diff "<SCENARIO-KEY>"
# Output shows: scenario name/description changes and request changes
```

#### Q: How do I see full raw diffs for all requests in a scenario?

**A:** Use the `--full` flag to display complete raw HTTP diffs for all requests in the scenario.

**Example:**

```bash
# Show full raw request diffs within a scenario
stoobly-agent scenario snapshot diff "<SCENARIO-KEY>" --full

# Show raw diffs for all scenarios with changes
stoobly-agent scenario snapshot diff --full
```

#### Q: How do I see diffs for all scenarios that have changed?

**A:** Run `scenario snapshot diff` without specifying a scenario key to see diffs for all scenarios with snapshots.

**Example:**

```bash
# Show diffs for all scenarios with changes
stoobly-agent scenario snapshot diff

# Show full raw diffs for all scenarios
stoobly-agent scenario snapshot diff --full
```

#### Q: When should I use diff before resetting?

**A:** Always check the diff before resetting to ensure you want to discard the changes. The diff shows you exactly what will be lost.

**Example:**

```bash
# Check what changed
stoobly-agent request snapshot diff "<REQUEST-KEY>"

# Review the changes carefully

# If you want to keep the changes, don't reset
# If you want to discard them and go back to snapshot:
stoobly-agent request snapshot reset "<REQUEST-KEY>"
```

#### Q: Can I use diff to find requests that match a pattern?

**A:** The `request snapshot diff` command will show diffs for all requests with snapshots. You can filter by specifying a request key or by piping output.

**Example:**

```bash
# Show diffs for all requests to find which ones changed
stoobly-agent request snapshot diff

# Save diffs to a file for review
stoobly-agent request snapshot diff --full > changes.txt
```

***

### Copying Snapshots

#### Q: How do I copy snapshots to a different directory?

**A:** Use `snapshot copy` with the destination path to copy snapshots between data directories.

**Example:**

```bash
# Copy request snapshot to different directory
stoobly-agent snapshot copy /path/to/other/project --request-key "<REQUEST-KEY>"

# Copy scenario snapshot
stoobly-agent snapshot copy /path/to/other/project --scenario-key "<SCENARIO-KEY>"
```

#### Q: How do I copy multiple requests at once?

**A:** Use multiple `--request-key` options to copy several requests.

**Example:**

```bash
stoobly-agent snapshot copy /path/to/destination \
  --request-key "<REQUEST-KEY-1>" \
  --request-key "<REQUEST-KEY-2>" \
  --request-key "<REQUEST-KEY-3>"
```

#### Q: How do I copy multiple scenarios at once?

**A:** Use multiple `--scenario-key` options to copy several scenarios.

**Example:**

```bash
stoobly-agent snapshot copy /path/to/destination \
  --scenario-key "<SCENARIO-KEY-1>" \
  --scenario-key "<SCENARIO-KEY-2>" \
  --scenario-key "<SCENARIO-KEY-3>"
```

#### Q: How do I copy both requests and scenarios together?

**A:** Combine both `--request-key` and `--scenario-key` options.

**Example:**

```bash
stoobly-agent snapshot copy /path/to/destination \
  --request-key "<REQUEST-KEY-1>" \
  --request-key "<REQUEST-KEY-2>" \
  --scenario-key "<SCENARIO-KEY-1>" \
  --scenario-key "<SCENARIO-KEY-2>"
```

#### Q: Why would I copy snapshots to a different directory?

**A:** Copying snapshots is useful for moving tests between projects, creating backups, or setting up separate test environments.

**Example:**

```bash
# Copy production tests to staging environment
stoobly-agent snapshot copy /path/to/staging \
  --scenario-key "<SCENARIO-KEY-1>" \
  --scenario-key "<SCENARIO-KEY-2>"

# In staging directory
cd /path/to/staging
stoobly-agent snapshot apply
```

***

### Pruning Snapshots

#### Q: How do I clean up deleted snapshots?

**A:** Use `snapshot prune` to remove snapshot files for deleted resources.

**Example:**

```bash
stoobly-agent snapshot prune
```

#### Q: How do I preview what will be pruned without deleting?

**A:** Use the `--dry-run` flag to see what would be deleted.

**Example:**

```bash
# Preview prune operation
stoobly-agent snapshot prune --dry-run

# Actually prune
stoobly-agent snapshot prune
```

#### Q: When should I prune snapshots?

**A:** Prune after deleting scenarios or requests to keep your snapshot directory clean and your Git repository size manageable.

**Example:**

```bash
# Delete a scenario
stoobly-agent scenario delete old-scenario

# Clean up its snapshots
stoobly-agent snapshot prune

# Commit the cleanup
git add .stoobly/snapshots/
git commit -m "Remove old scenario snapshots"
```

***

### Version Control Workflows

#### Q: How do I set up snapshots for Git?

**A:** Create snapshots and add the `.stoobly/snapshots/` directory to Git.

**Example:**

```bash
# Create scenario with requests
stoobly-agent scenario create "User Login"
# ... add requests ...

# Create snapshot
stoobly-agent scenario snapshot create user-login --decode

# Add to Git
git add .stoobly/snapshots/
git commit -m "Add user login test scenario"
git push
```

#### Q: How do team members use snapshots from Git?

**A:** Pull the repository and apply snapshots to get the tests.

**Example:**

```bash
# Clone or pull repository
git clone <repo-url>
cd <repo>

# Apply all snapshots
stoobly-agent snapshot apply

# Use the tests
stoobly-agent scenario list
stoobly-agent scenario test user-login
```

#### Q: How do I update existing snapshots in Git?

**A:** Re-create the snapshot and commit the changes.

**Example:**

```bash
# Make changes to scenario (add/remove requests)
stoobly-agent record <new-request> --scenario-key "<SCENARIO-KEY>"

# Update snapshot
stoobly-agent scenario snapshot create user-login --decode

# Commit changes
git add .stoobly/snapshots/
git commit -m "Update user login with new endpoint"
git push
```

#### Q: How do I handle merge conflicts in snapshots?

**A:** Resolve conflicts manually in snapshot files or re-create snapshots from one version.

**Example:**

```bash
# Conflict occurs during merge
git merge feature-branch

# Option 1: Manual resolution
# Edit conflicted snapshot files in .stoobly/snapshots/
git add .stoobly/snapshots/
git commit

# Option 2: Re-create from one version
git checkout --theirs .stoobly/snapshots/scenarios/<SNAPSHOT-UUID>
stoobly-agent snapshot apply "<SNAPSHOT-UUID>"
# Test and verify
git add .stoobly/snapshots/
git commit
```

#### Q: Should I commit snapshot files or the database?

**A:** Commit snapshot files in `.stoobly/snapshots/`, NOT the database files in `.stoobly/db/`. Add `.stoobly/db/` to `.gitignore`.

**Example:**

```bash
# .gitignore
.stoobly/db/
.stoobly/logs/
.stoobly/tmp/

# DO commit:
# .stoobly/snapshots/
```

***

### Advanced Snapshot Operations

#### Q: How do I export snapshots for backup?

**A:** Copy the `.stoobly/snapshots/` directory or use snapshot copy.

**Example:**

```bash
# Option 1: Direct copy
tar -czf snapshots-backup-$(date +%Y%m%d).tar.gz .stoobly/snapshots/

# Option 2: Use snapshot copy
stoobly-agent snapshot copy /backup/location \
  --scenario-key "<SCENARIO-KEY-1>" \
  --scenario-key "<SCENARIO-KEY-2>"
```

#### Q: How do I share snapshots across projects?

**A:** Use snapshot copy to move snapshots between project directories.

**Example:**

```bash
# In project A
stoobly-agent snapshot copy /path/to/project-b \
  --scenario-key "<SCENARIO-KEY>"

# In project B
cd /path/to/project-b
stoobly-agent snapshot apply
```

#### Q: How do I create snapshots in CI/CD?

**A:** Record requests during CI, create snapshots, and commit them back if needed.

**Example:**

```bash
#!/bin/bash
# CI/CD snapshot creation

# Run application and record tests
stoobly-agent run --intercept --intercept-mode record &
AGENT_PID=$!

# Run test suite (gets recorded)
npm test

# Stop agent
kill $AGENT_PID

# Create snapshots
for scenario in $(stoobly-agent scenario list --format json | jq -r '.[].key'); do
  stoobly-agent scenario snapshot create $scenario --decode
done

# Check if snapshots changed
if git diff --exit-code .stoobly/snapshots/; then
  echo "No snapshot changes"
else
  echo "Snapshots updated"
  # Optionally commit back to repo
fi
```

#### Q: How do I validate snapshots in CI/CD?

**A:** Apply snapshots and run tests to ensure they're valid.

**Example:**

```bash
#!/bin/bash
# CI/CD snapshot validation

# Apply all snapshots
if ! stoobly-agent snapshot apply; then
  echo "Failed to apply snapshots"
  exit 1
fi

# List applied snapshots
stoobly-agent request snapshot list

# Test scenarios from snapshots
for scenario in $(stoobly-agent scenario list --format json | jq -r '.[].key'); do
  echo "Testing scenario: $scenario"
  if ! stoobly-agent scenario test $scenario --strategy diff; then
    echo "Failed: $scenario"
    exit 1
  fi
done

echo "All snapshot scenarios validated"
```

***

### Troubleshooting

#### Q: What do I do if snapshot apply fails?

**A:** Check for errors, use force option, or manually inspect the snapshot files.

**Example:**

```bash
# Try with force
stoobly-agent snapshot apply --force

# List pending snapshots to see what's not applied
stoobly-agent request snapshot list --pending

# Check for specific errors
stoobly-agent snapshot apply "<SNAPSHOT-UUID>"
```

#### Q: How do I verify snapshot integrity?

**A:** Use snapshot create to verify and fix snapshot formatting.

**Example:**

```bash
# Verify and fix request snapshot
stoobly-agent request snapshot create "<REQUEST-KEY>"

# Verify and fix scenario snapshot
stoobly-agent scenario snapshot create "<SCENARIO-KEY>"

# List all snapshots and update each
for uuid in $(stoobly-agent request snapshot list --format json | jq -r '.[].uuid'); do
  stoobly-agent request snapshot create $uuid
done
```

#### Q: How do I find which snapshot corresponds to a request?

**A:** List snapshots with search or match request keys to UUIDs.

**Example:**

```bash
# Search request snapshots by path
stoobly-agent request snapshot list --search "/api/users"

# List with specific format
stoobly-agent request snapshot list --select uuid --select path --select snapshot
```

***

### Best Practices

#### Q: When should I create snapshots?

**A:** Create snapshots after recording important test flows, before releases, and when sharing tests with the team.

**Example:**

```bash
# After recording a critical flow
stoobly-agent record <requests> --scenario-key "<SCENARIO-KEY>"
stoobly-agent scenario snapshot create "<SCENARIO-KEY>" --decode
git add .stoobly/snapshots/ && git commit -m "Add checkout flow"

# Before release
./create-all-snapshots.sh
git tag -a v1.0.0 -m "Release 1.0.0 with test snapshots"
```

#### Q: How often should I prune snapshots?

**A:** Prune after deleting old tests or periodically to keep the repository clean.

**Example:**

```bash
# Monthly cleanup
stoobly-agent snapshot prune --dry-run  # Preview
stoobly-agent snapshot prune            # Execute
git add .stoobly/snapshots/
git commit -m "Prune deleted snapshots"
```

#### Q: When should I decode snapshots?

**A:** Use `--decode` when creating snapshots for better Git diffs and readability.

**Example:**

```bash
# Always use --decode for version control
stoobly-agent scenario snapshot create "<SCENARIO-KEY>" --decode
stoobly-agent request snapshot create "<REQUEST-KEY>" --decode
```

***

### Quick Reference

#### Q: What are the most common snapshot commands?

**A:** Here's a quick reference of frequently used commands:

**Example:**

```bash
# List request snapshots
stoobly-agent request snapshot list
stoobly-agent request snapshot list --search "/api/users"
stoobly-agent request snapshot list --pending
stoobly-agent request snapshot list --scenario-key "<SCENARIO-KEY>"

# List scenario snapshots
stoobly-agent scenario snapshot list
stoobly-agent scenario snapshot list --search "login"
stoobly-agent scenario snapshot list --pending

# Create snapshots
stoobly-agent request snapshot create "<REQUEST-KEY>"
stoobly-agent request snapshot create "<REQUEST-KEY>" --decode
stoobly-agent scenario snapshot create "<SCENARIO-KEY>"
stoobly-agent scenario snapshot create "<SCENARIO-KEY>" --decode

# Reset snapshots
stoobly-agent request snapshot reset "<REQUEST-KEY>"
stoobly-agent request snapshot reset "<REQUEST-KEY>" --force
stoobly-agent scenario snapshot reset "<SCENARIO-KEY>"
stoobly-agent scenario snapshot reset "<SCENARIO-KEY>" --force

# Diff snapshots
stoobly-agent request snapshot diff "<REQUEST-KEY>"
stoobly-agent request snapshot diff --full
stoobly-agent scenario snapshot diff "<SCENARIO-KEY>"

# Apply all snapshots
stoobly-agent snapshot apply
stoobly-agent snapshot apply "<SNAPSHOT-UUID>"
stoobly-agent snapshot apply --force

# Copy snapshots
stoobly-agent snapshot copy /path/to/dest --scenario-key "<SCENARIO-KEY>"
stoobly-agent snapshot copy /path/to/dest --request-key "<REQUEST-KEY>"

# Prune snapshots
stoobly-agent snapshot prune --dry-run
stoobly-agent snapshot prune
```

***

### Integration Examples

#### Q: How do I automate snapshot creation?

**A:** Use a script to create snapshots for all scenarios.

**Example:**

```bash
#!/bin/bash
# Create snapshots for all scenarios

for scenario in $(stoobly-agent scenario list --format json | jq -r '.[].key'); do
  echo "Creating snapshot for: $scenario"
  stoobly-agent scenario snapshot create $scenario --decode
done

echo "All snapshots created"
```

#### Q: How do I sync snapshots across environments?

**A:** Use Git to sync and snapshot copy for different data directories.

**Example:**

```bash
# Development: Create and push snapshots
stoobly-agent scenario snapshot create critical-tests --decode
git add .stoobly/snapshots/ && git commit -m "Update tests" && git push

# Staging: Pull and apply
git pull
stoobly-agent snapshot apply

# Production: Copy from staging
stoobly-agent snapshot copy /production/path --scenario-key "<SCENARIO-KEY>"
```


# Installing the Agent

How to install Stoobly agent either with pip, Docker, or from source

Stoobly [agent](/core-concepts/agent) provides the following functionality:

* Acts as a proxy to Intercept HTTP(s) requests
* Serves as a CLI to view and manage recorded requests
* Provides a local web UI to view and manage recorded requests

## Installation Methods

We support three different installation methods:

### Recommended

{% content-ref url="/pages/BLH7AQGHe8IJ2wKEXMaq" %}
[Installation with pipx](/getting-started/installing-the-agent/installation-with-pipx)
{% endcontent-ref %}

### Alternative

{% content-ref url="/pages/wOXMShUcNiQ8lV0UujvT" %}
[Installation with Docker](/getting-started/installing-the-agent/installation-with-docker)
{% endcontent-ref %}

{% content-ref url="/pages/2SJjytrzgobojvS47VfY" %}
[Installation from Source](/developer-guide/installation-from-source)
{% endcontent-ref %}

## Next Steps

You're all setup! Depending on your use case, you may want to take a look at:

{% tabs %}
{% tab title="API Mocking" %}
{% content-ref url="/pages/XRMveeqrNM5K07qs5H8k" %}
[How to Record Requests](/guides/how-to-record-requests)
{% endcontent-ref %}
{% endtab %}

{% tab title="E2E Testing" %}
{% content-ref url="/pages/Ri9aZJJVXgxuyy67a3tW" %}
[How to Integrate E2E Testing](/guides/how-to-integrate-e2e-testing)
{% endcontent-ref %}
{% endtab %}
{% endtabs %}


# Installation with pipx

How to use pip to install Stoobly

## Prerequisite

### Install supported Python version

{% hint style="info" %}
Our official Python support is 3.12, 3.13, and 3.14.
{% endhint %}

{% hint style="warning" %}
If none of the supported Python versions are available on your system, you will need to install one using `pyenv` . Otherwise, skip to the next section.
{% endhint %}

To install a specific Python version, first install [pyenv](https://github.com/pyenv/pyenv).

{% stepper %}
{% step %}
**Install specific Python version**

```bash
pyenv install 3.13.0
pyenv local 3.13.0
```

{% endstep %}

{% step %}
**Switch Python version**

```bash
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv init -)"
```

{% endstep %}
{% endstepper %}

### Install pipx

To install [pipx](https://pipx.pypa.io/stable/), either follow the [official installation steps](https://pipx.pypa.io/stable/installation/) or run the following commands:

{% tabs %}
{% tab title="macOS" %}

```bash
brew install pipx
pipx ensurepath
source ~/.bashrc
```

{% endtab %}

{% tab title="Linux" %}

```bash
python3 -m pip install --user pipx
python3 -m pipx ensurepath
source ~/.bashrc
```

{% endtab %}
{% endtabs %}

## Install

To install the agent, run:

```bash
pipx install stoobly-agent --python python3
```

This will use pipx to download the agent from our [PyPI Python Package Index](https://pypi.org/project/stoobly-agent).

## Update

To update the agent, run:

```bash
pipx upgrade stoobly-agent
```

## Verify

```bash
stoobly-agent --help
```

## Next Steps

You're all setup! Depending on your use case, you may want to take a look at:

{% tabs %}
{% tab title="API Mocking" %}
{% content-ref url="/pages/XRMveeqrNM5K07qs5H8k" %}
[How to Record Requests](/guides/how-to-record-requests)
{% endcontent-ref %}
{% endtab %}

{% tab title="E2E Testing" %}
{% content-ref url="/pages/Ri9aZJJVXgxuyy67a3tW" %}
[How to Integrate E2E Testing](/guides/how-to-integrate-e2e-testing)
{% endcontent-ref %}
{% endtab %}
{% endtabs %}


# Installation with Docker

How to use Docker to intall Stoobly

## Prerequisite

Docker first must be installed. Refer to the official Docker install instructions [here](https://docs.docker.com/engine/install).

## Install

To install the agent, pull the following Docker image.

{% tabs %}
{% tab title="macOS" %}

```bash
docker pull stoobly/agent
```

{% endtab %}

{% tab title="Linux" %}

```bash
docker pull stoobly/agent
```

{% endtab %}
{% endtabs %}

## Update

To update the agent, re-pull the Docker image.

{% tabs %}
{% tab title="macOS" %}

```bash
docker pull stoobly/agent
```

{% endtab %}

{% tab title="Linux" %}

```bash
docker pull stoobly/agent
```

{% endtab %}
{% endtabs %}

## Verify

```bash
docker run \
    -v ~/.stoobly:/home/stoobly/.stoobly \
    stoobly/agent \
    stoobly-agent --help
```

## Next Steps

You're all setup! Depending on your use case, you may want to take a look at:

{% tabs %}
{% tab title="API Mocking" %}
{% content-ref url="/pages/XRMveeqrNM5K07qs5H8k" %}
[How to Record Requests](/guides/how-to-record-requests)
{% endcontent-ref %}
{% endtab %}

{% tab title="E2E Testing" %}
{% content-ref url="/pages/Ri9aZJJVXgxuyy67a3tW" %}
[How to Integrate E2E Testing](/guides/how-to-integrate-e2e-testing)
{% endcontent-ref %}
{% endtab %}
{% endtabs %}


# Integrating the JavaScript Client

An introduction to the Stoobly JavaScript client library for E2E testing

The Stoobly JavaScript library (npm package `stoobly`) lets you record, mock, and test HTTP requests directly from end-to-end testing frameworks like Playwright and Cypress. Use it alongside a `stoobly-agent` scaffold workflow to control interception from your tests.

## What is the Stoobly JavaScript client library?

The `stoobly` npm package (the Stoobly JavaScript client library) integrates with the [stoobly-agent](/getting-started/installing-the-agent) to enable:

* **Recording** — Capture HTTP requests and responses for later replay
* **Mocking** — Return pre-recorded responses instead of hitting real APIs
* **Replay** — Replay recorded requests
* **Testing** — Validate API responses against recorded data

## Prerequisite

Before using the JavaScript client library, set up Stoobly for E2E testing:

1. [Install the agent](/getting-started/installing-the-agent) — `stoobly-agent` must be available on your machine or in CI
2. [Integrate E2E testing](/guides/how-to-integrate-e2e-testing) — create a scaffold app and services with `--plugin playwright` or `--plugin cypress`

The JavaScript client library builds on that scaffold setup. It does not replace creating the app, services, or workflows.

## Installation

```bash
npm install stoobly --save-dev
```

Requires Node.js 18 or higher. See [Setup](/faq/scaffold/e2e-testing/js-client/setup) for import patterns and framework-specific install steps.

## Integrate with your test framework

After installing the package, wire Stoobly into your E2E tests:

* [Playwright](/faq/scaffold/e2e-testing/js-client/playwright) — `playwrightInterceptor()`, `withPage()`, `withContext()`, and recording
* [Cypress](/faq/scaffold/e2e-testing/js-client/cypress) — `cypressInterceptor()`, `enable()`, and recording

See [Setup](/faq/scaffold/e2e-testing/js-client/setup) for import patterns and framework-specific install steps.

## Running the Agent from npm scripts

With your scaffold in place, start the workflow that matches your test mode (`mock`, `record`, or `test`) before running tests. Rather than starting and stopping it by hand in a separate terminal, wrap it in `package.json` scripts so it fits your existing `npm test` flow:

```json
{
  "scripts": {
    "stoobly:mock": "stoobly-agent scaffold workflow up mock --detached",
    "stoobly:mock:down": "stoobly-agent scaffold workflow down mock",
    "test:mock": "npm run stoobly:mock && (npx playwright test; code=$?; npm run stoobly:mock:down; exit $code)"
  }
}
```

See [npm scripts](/faq/scaffold/e2e-testing/js-client/npm-scripts) for the full set of recommended scripts, including record/test variants, diagnostics, and CI setup.

## Configure interception

[Configuration](/faq/scaffold/e2e-testing/js-client/configuration) covers URL patterns, scenarios, sessions, recording options, and how to start and stop interception from test code.

## Reference

* [JavaScript Client Library FAQ](/faq/scaffold/e2e-testing/js-client) — full how-to index
* [TypeDoc reference](https://stoobly.github.io/stoobly-js/) — class, method, and type documentation
* [Troubleshooting & examples](/faq/scaffold/e2e-testing/js-client/troubleshooting) — debugging and complete examples
* [GitHub README](https://github.com/Stoobly/stoobly-js/blob/main/README.md) — quick-start code samples


# Configuring an AI Assistant

## Overview

If you're using an AI coding assistant (like Cursor, Windsurf, GitHub Copilot, or similar tools), you can configure it to use Stoobly's documentation as an authoritative reference. This ensures the AI provides accurate, up-to-date answers about Stoobly commands and workflows.

## Why Use LLM Rules?

LLM rules help your AI assistant:

* **Provide accurate CLI commands** with proper syntax
* **Reference official documentation** instead of hallucinating features
* **Answer questions faster** by consulting the structured FAQ
* **Stay up-to-date** with the latest Stoobly features and best practices

## Setting Up LLM Rules

### Step 1: Get the Rules File

The Stoobly documentation includes a pre-built LLM context file designed for AI assistants. You have two options:

#### Option 1: Clone the Documentation Repository (Recommended)

Clone the Stoobly docs repository to get the latest rules file locally:

{% hint style="info" %}
If `.stoobly` does not exist, create it first: `mkdir -p .stoobly`
{% endhint %}

```bash
git clone https://github.com/Stoobly/stoobly-docs.git .stoobly/docs
```

The rules file will be located at:

```
.stoobly/docs/getting-started/configuring-an-ai-assistant/llm-rules.md
```

{% hint style="info" %}
If the repository is version controlled using git, add .stoobly/docs to the .gitignore file
{% endhint %}

**Benefits:**

* Always have the latest documentation locally
* Works offline once cloned
* Can pull updates with `git pull`
* Better for AI assistants that work with local files

#### Option 2: Reference the Online Version

Point your AI assistant directly to the online documentation:

```
https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/llm-rules.md
```

**Benefits:**

* No setup required
* Always points to the latest published version
* Good for AI assistants that can fetch web content

#### What's in the Rules File?

The LLM rules file contains:

* An index of common Stoobly questions and commands
* Links to detailed documentation pages
* CLI command examples and syntax
* Best practices for answering Stoobly-related questions

### Step 2: Configure Your AI Assistant

The configuration method depends on your AI tool:

{% tabs %}
{% tab title="Multi-Tool (AGENTS.md)" %}
**Using AGENTS.md (Recommended for Multi-Tool Support)**

[AGENTS.md](https://agents.md/) is an emerging open format for AI assistant configuration supported by many AI coding tools. Choose this option if you use multiple AI coding assistants or want a single, standardized configuration file that works across different tools.

**Supported tools include:**

* GitHub Copilot
* Cursor
* VS Code
* OpenAI Codex
* Google Gemini CLI

**Using AGENTS.md**

1. Create an `AGENTS.md` file in your project root
2. Add one of the following configurations to instruct your AI assistant to read the LLM context file:

**If you cloned the docs locally:**

```
# Stoobly Project Context

For all Stoobly-related questions, ALWAYS read the file .stoobly/docs/getting-started/configuring-an-ai-assistant/llm-rules.md first before responding. Do not answer from memory.
```

**If using the online version:**

```
# Stoobly Project Context

For all Stoobly-related questions, ALWAYS fetch https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/llm-rules.md first.  Do not answer from memory.
```

3. Save the file and restart your editor if needed
   {% endtab %}

{% tab title="Claude Code" %}
**Using Claude Code**

Claude Code supports custom instructions through the `CLAUDE.md` files:

1. Create or edit `~/.claude/CLAUDE.md` (global user configuration) or `CLAUDE.md` (project-specific) in your repo
2. Add one of the following configurations:

**If you cloned the docs locally:**

```
For all Stoobly-related questions, ALWAYS read the file .stoobly/docs/getting-started/configuring-an-ai-assistant/llm-rules.md first before responding. Do not answer from memory.
```

**If using the online version:**

```
For all Stoobly-related questions, ALWAYS fetch https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/llm-rules.md first.  Do not answer from memory.
```

3. Save the file - Claude Code will automatically use these rules in your next conversation
4. You can also reference the rules file explicitly in your prompts
   {% endtab %}

{% tab title="Cursor" %}
**Using Cursor**

1. Open your Cursor settings or create a `.cursorrules` file in your project root
2. Add one of the following rules to instruct Cursor to read the LLM context file:

**If you cloned the docs locally:**

```
For all Stoobly-related questions, ALWAYS read the file .stoobly/docs/getting-started/configuring-an-ai-assistant/llm-rules.md first before responding. Do not answer from memory.
```

**If using the online version:**

```
For all Stoobly-related questions, ALWAYS fetch https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/llm-rules.md first.  Do not answer from memory.
```

3. Save the file and restart Cursor if needed
   {% endtab %}

{% tab title="Windsurf" %}
**Using Windsurf**

1. Create a `.windsurfrules` file in your project root
2. Add one of the following rules to instruct Windsurf to read the LLM context file:

**If you cloned the docs locally:**

```
For all Stoobly-related questions, ALWAYS read the file .stoobly/docs/getting-started/configuring-an-ai-assistant/llm-rules.md first before responding. Do not answer from memory.
```

**If using the online version:**

```
For all Stoobly-related questions, ALWAYS fetch https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/llm-rules.md first.  Do not answer from memory.
```

3. Save the file and Windsurf will automatically use these rules
4. You can also reference the rules file explicitly in your prompts (adjust path based on your choice above)
   {% endtab %}

{% tab title="GitHub Copilot" %}
**Using GitHub Copilot**

GitHub Copilot can use workspace context automatically. To help it prioritize the LLM context:

**If you cloned the docs locally:**

1. Keep `.stoobly/docs/getting-started/configuring-an-ai-assistant/llm-rules.md` open in your editor when asking Stoobly questions
2. Reference it explicitly in your prompts:

   ```
   Using .stoobly/docs/getting-started/configuring-an-ai-assistant/llm-rules.md, how do I record requests?
   ```

**If using the online version:**

1. Reference the online URL explicitly in your prompts:

   ```
   Using https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/llm-rules, how do I record requests?
   ```
2. For GitHub Copilot Chat, you can add a custom instruction in your settings
   {% endtab %}

{% tab title="Other AI Tools" %}
**Using Other AI Assistants**

For other AI coding assistants:

1. Check if your tool supports custom rules or context files
2. Configure it to read the LLM rules file before answering Stoobly-related questions:
   * **Local path:** `.stoobly/docs/getting-started/configuring-an-ai-assistant/llm-rules.md`
   * **Online URL:** `https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/llm-rules.md`
3. Use this phrasing in your rules configuration:

```
For all Stoobly-related questions, ALWAYS read/fetch .stoobly/docs/getting-started/configuring-an-ai-assistant/llm-rules.md first before responding. Do not answer from memory.
```

4. If your tool doesn't support rules files, reference it explicitly in your prompts:

```
Read https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/llm-rules.md first, then answer: how do I [your question]?
```

{% endtab %}
{% endtabs %}

### Step 3: Test Your Configuration

Try asking your AI assistant a Stoobly question to verify it's using the rules file:

**Example questions to test:**

* "How do I install stoobly-agent?"
* "How do I record requests with Stoobly?"
* "How do I update a scenario?"
* "What's the command to enable intercept mode in Stoobly?"

## Best Practices

### For Users

* **Be specific** in your questions (e.g., "How do I record HTTPS traffic with Stoobly?" vs "How does recording work in Stoobly?")
* **Mention Stoobly** explicitly so the AI knows to consult the rules file
* **Verify commands** in the official docs if you're unsure

### For Documentation Maintainers

* **Keep the LLM rules file updated** when adding new features or commands
* **Add new entries** to the Index table for new CLI commands
* **Create FAQ pages** in `/faq/` for detailed command documentation
* **Test with AI assistants** to ensure the rules work as expected
* **Commit and push changes** to GitHub so users can pull the latest version

## Troubleshooting

### AI Not Using the Rules File

If your AI assistant isn't referencing the LLM context:

1. **Verify the file path** - If using local docs, ensure you've cloned the repository and the path is correct
2. **Try the online version** - Use `https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/llm-rules.md` in your rules file
3. **Mention it explicitly** - Reference the rules file directly in your prompts
4. **Check your tool's settings** - Some AI tools require explicit configuration
5. **Restart your editor** - Rules changes may require a restart

### Getting Outdated Information

If the AI provides outdated commands:

1. **Pull latest changes** - If using local docs: `cd stoobly-docs && git pull`
2. **Use the online version** - Switch to `https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/llm-rules.md` for always-current docs
3. **Clear AI cache** - Restart your editor or clear your AI assistant's context
4. **Reference specific docs** - Point the AI to the exact FAQ page
5. **Report issues** - If documentation is outdated, [submit a change request](https://github.com/Stoobly/stoobly-docs/issues)

### Commands Not Working

If suggested commands fail:

1. **Verify installation** - Run `stoobly-agent --version` to check if installed
2. **Check syntax** - Compare with examples in the [FAQ](https://docs.stoobly.com/faq)
3. **Use `--help`** - Run `stoobly-agent <command> --help` for official syntax

## Next Steps

You're all setup! Depending on your use case, you may want to take a look at:

{% tabs %}
{% tab title="API Mocking" %}
{% content-ref url="/pages/XRMveeqrNM5K07qs5H8k" %}
[How to Record Requests](/guides/how-to-record-requests)
{% endcontent-ref %}
{% endtab %}

{% tab title="E2E Testing" %}
{% content-ref url="/pages/Ri9aZJJVXgxuyy67a3tW" %}
[How to Integrate E2E Testing](/guides/how-to-integrate-e2e-testing)
{% endcontent-ref %}
{% endtab %}
{% endtabs %}


# LLM Rules

#### 1. Purpose

You are an assistant designed to help users understand and use **Stoobly**, a developer platform for **recording, mocking, replaying, and testing API requests**.\\

**📍 Documentation Source:** Use **"Local Docs"** if you accessed this file via a filesystem path, or **"Remote Docs"** if you accessed it via a URL.

When users ask a question about Stoobly, you should:

* **ALWAYS start by reading the Index section (Section 5 below)** — Match the user's question against the "Example Questions" column in the Index or Skills table to identify the relevant documentation page or skill.
* **Fetch and read the matching page or skill** from the appropriate table before responding. Do not answer from memory.
* **Check for user-specific setup context** — If accessible, examine `.stoobly/services/.config.yml` only to tailor tone/phrasing (runtime, proxy mode) — never as the primary way to answer the question (see Section 5 for detailed workflow).
* **Fetch additional context if needed** — If the primary page doesn't fully answer the question, consider related guides for supplementary context.
  * Local: Read [../../SUMMARY.md](https://github.com/Stoobly/stoobly-docs/tree/main/SUMMARY.md) to discover related guides and core concepts
  * Remote: Fetch <https://docs.stoobly.com/llms.txt> to discover related guides (`/guides/`) and core concepts (`/core-concepts/`)

When responding:

* Prioritize answering with complete CLI command examples and descriptions.
* Answer concisely, accurately, and with actionable guidance.
* Provide links to the relevant documentation section when possible.
* For scaffold setup questions, recommend a declarative `.stoobly/scaffold.yml` applied with `scaffold apply` first; present individual commands like `scaffold app create` / `scaffold service create` as the alternative.

If you are unsure or the docs do not contain the information, respond with:

> “I’m not certain about that yet. You can check the Stoobly Docs for the latest info: <https://docs.stoobly.com”>

***

> **🚫 Hard constraint:** Never read or `cat` raw `.config.yml` / scaffold directory files — directly, during "research," or by instructing a subagent/another agent to do so — to determine service, workflow, or config state. Always run the CLI instead (`scaffold service list`, `scaffold service show`, `scaffold workflow show`). Raw files can be stale, incomplete, or missing defaults the CLI applies — only the CLI reflects actual resolved state.

***

#### 2. Overview of Stoobly

**Stoobly** is an API mock framework with seamless CI setup that enables E2E testing. Stoobly helps developers:

* **Record API traffic** from applications, tests, or environments.
* **Replay** those requests locally or in CI to ensure consistency.
* **Mock** APIs by intercepting requests and returning stored responses.
* **Integrate** with end-to-end (E2E) testing tools like Playwright, Cypress, or Puppeteer.
* **Debug** and validate API behavior, especially across staging and production.

**Common uses:**

* Test APIs when external services are unreliable or slow.
* Capture and replay traffic for regression testing.
* Create stable E2E tests without flakiness caused by network variability.
* Build workflows that simulate complex multi-step API interactions.

***

#### 3. Response Style

When answering:\
✅ Prefer accurate and practical responses.\
✅ Include brief explanations when helpful for clarity.\
✅ Link to relevant docs (e.g., `https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/`).\
✅ Use Markdown formatting for clarity (bullets, code blocks).\
✅ Prefer actionable examples over abstract explanations.\
✅ Always prefix Stoobly CLI commands with 'stoobly-agent' (e.g., 'stoobly-agent scaffold app create', not 'scaffold app create').\
❌ Do not hallucinate or assume undocumented features.\
❌ Do not answer questions about scaffold state (services, workflows, config) by reading or `cat`-ing raw `.config.yml` / scaffold directory files yourself, or by instructing a subagent/research step to do so on your behalf. Use the documented CLI command instead (e.g. `scaffold service list`, `scaffold service show`, `scaffold workflow show`). See the hard constraint in Section 1.

***

#### 4. Example Answer Template

Use this template as guidance, but adapt structure and formatting to match the question. When it helps the reader compare choices, label alternatives (for example, "Option 1", "Option 2", "Option 3"); otherwise summarize the single best approach.

**Q:** Why do I get a 499 error when replaying with Stoobly?\
**A:** A 499 means the client closed the connection before the server responded — often due to timeouts or misconfigured network routes.\
Try:

1. Increasing the timeout in your test runner or Stoobly CLI.
2. Verifying that the target API endpoint is reachable.
3. Checking if your workflow requests depend on earlier failed steps.

More details: Stoobly Troubleshooting Guide

**Q:** How do I record requests with Stoobly?\
**A:** First, optionally create a scenario to organize your requests, then record.

**Step 1 (Optional):** Create a scenario:

`stoobly-agent scenario create "my-user-flow"`

**Step 2:** Record requests using one of these options:

**Option 1:** Use the default intercept workflow:

1. `stoobly-agent run`
2. `stoobly-agent intercept set --mode record`
3. `stoobly-agent intercept enable`

**Option 2:** Record from the CLI in a single command:

`stoobly-agent record https://example.com/path --scenario-key "<SCENARIO-KEY>"`

More details: [How to Record Requests](https://docs.stoobly.com/guides/how-to-record-requests/), [Stoobly Troubleshooting Guide](https://docs.stoobly.com/guides/how-to-mock-apis/troubleshooting)

**Q:** What Stoobly services do I have?\
**A:**\
❌ Wrong: Reading `.stoobly/services/*/.config.yml` directly (or asking a subagent to) and presenting that as the answer.\
✅ Right: Run `stoobly-agent scaffold service list` and present its output.

#### 5. Index

**⚠️ CRITICAL: Use the Index and Skills tables for ALL CLI-related questions.**

When a user asks a CLI-related Stoobly question, follow this workflow:

1. **Scan the "Example Questions" column** in the Index and Skills tables to find questions that match the user's intent.
   * Look for keywords, command names, or concepts mentioned in the user's question.
   * Also check the "Primary Commands" column for command name matches.
   * For multi-step troubleshooting workflows (especially E2E test failures), prefer the **Skills** table.
   * Example: User asks "How do I record requests?" → Match to "How do I record requests with Stoobly?" in the Intercept row of the Index table.
2. **Check for user-specific setup context** (if accessible), but only to tailor phrasing of the answer identified in step 1 — not as a way to answer the question itself:
   * If you can access the user's filesystem, check if `.stoobly/services/.config.yml` exists:
     * If the file doesn't exist, the user is not using a scaffolded application
     * If the file exists, check the `APP_RUNTIME` property to determine which runtime they're using (`local` or `docker`)
     * If the file exists, check the `APP_PROXY_MODE` property to determine the setup is running as a forward or reverse proxy
     * Use this context to tailor your answer to their actual configuration
   * **Do not** use this file (or any other scaffold directory file) to answer questions about what services exist, their hostnames/ports, or other config details — those questions are answered via step 1's matched CLI command (e.g. `scaffold service list`, `scaffold service show`), not by reading files directly. This applies even during read-only research or when delegating to a subagent — see the hard constraint in Section 1.
3. **Identify the corresponding Page or Skill** from the matched row (e.g., "Intercept" or "Troubleshoot E2E Test").
4. **Determine your documentation source based on how you accessed this file:**
   * **If you accessed this file via a local filesystem path** (e.g., `.stoobly/docs/...`, `/home/user/...`, or any local path): → Use the **"Local Docs"** column paths (e.g., `../../faq/intercept.md`) → These are relative markdown files you can read directly from disk → For user-facing links, convert to the corresponding HTML page on `https://docs.stoobly.com/`
   * **If you accessed this file via a URL** (e.g., `https://docs.stoobly.com/...`): → Fetch from **"Remote Docs"** URLs, appending `.md` for efficiency (e.g., `https://docs.stoobly.com/faq/intercept.md`) → For user-facing links, use the HTML version without `.md` (e.g., `https://docs.stoobly.com/faq/intercept`)
5. **Reference the documentation or skill** using the appropriate docs link from that row to get the correct command syntax and examples.
   * **Prefer the FAQ page first** for single-topic questions. Use **Skills** for guided troubleshooting workflows. Use "Related Guides" only for supplementary context.
6. **Return the answer** following the Example Answer Template (Section 4) with:
   * Direct CLI command examples (tailored to their runtime if known from step 1)
   * Link to the referenced documentation page
   * Actionable guidance
7. **Fallback** to the documentation found in the `stoobly-agent` CLI by running the `stoobly-agent <PRIMARY_COMMAND> --help` for the user and analyzing the output.

**Example workflow (local access):**

* File accessed via: `.stoobly/docs/getting-started/configuring-an-ai-assistant/llm-rules.md`
* User asks: "How do I debug why a request is not being mocked?"
* Match found: "How to diagnose failed mocks or 499 responses" in the **Request** row
* Read from: `../../faq/request.md` (Local Docs column)
* Link user to: `https://docs.stoobly.com/faq/request`

**Example workflow (remote access):**

* File accessed via: `https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/llm-rules.md`
* User asks: "How do I debug why a request is not being mocked?"
* Match found: "How to diagnose failed mocks or 499 responses" in the **Request** row
* Fetch from: `https://docs.stoobly.com/faq/request.md` (Remote Docs column + .md)
* Link user to: `https://docs.stoobly.com/faq/request`

**Example workflow (skill, local access):**

* File accessed via: `.stoobly/docs/getting-started/configuring-an-ai-assistant/llm-rules.md`
* User asks: "My E2E test failed — how do I debug it?"
* Match found: "How do I troubleshoot E2E test failures?" in the **Troubleshoot E2E Test** row of the Skills table
* Read from: `Skills/stoobly-troubleshoot-e2e-test.md` (Local Docs column)
* Follow the skill's step-by-step instructions in order
* Link user to: `https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/Skills/stoobly-troubleshoot-e2e-test`

### Index Table

| Page                                                  | Primary Commands                                                                                                                                                                                                                                                                       | Example Questions                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | Local Docs                                                                                                         | Remote Docs                                                                   | Related Guides                                                                                                                                                                                                           |
| ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **FAQ**                                               | N/A                                                                                                                                                                                                                                                                                    | "What does a 499 error mean?", "I got a 499 error and nothing got mocked. Why?", "Where are requests stored?", "How do I report an issue?", "Is Stoobly a test framework?", "What are common terminologies?", "Where do I find the latest releases?"                                                                                                                                                                                                                                                                                                      | [../../faq/README.md](/faq)                                                                                        | <https://docs.stoobly.com/faq>                                                | [Core Concepts](https://docs.stoobly.com/core-concepts/)                                                                                                                                                                 |
| **CA Cert**                                           | `ca-cert install`, `ca-cert uninstall`, `ca-cert show`                                                                                                                                                                                                                                 | "Why is Stoobly failing to record HTTPS requests?", "How do I trust Stoobly's certificate?", "How do I install the CA certificate?"                                                                                                                                                                                                                                                                                                                                                                                                                       | [../../faq/ca-cert.md](/faq/ca-cert)                                                                               | <https://docs.stoobly.com/faq/ca-cert>                                        | [Proxy Configuration](https://docs.stoobly.com/guides/proxy-configuration/)                                                                                                                                              |
| **Config**                                            | `setting dump`, `config reset`, `config validate`                                                                                                                                                                                                                                      | "How do I change Stoobly's intercept policy?", "What config options does Stoobly have?", "How do I view my configuration?", "How do I reset configuration?"                                                                                                                                                                                                                                                                                                                                                                                               | [../../faq/config.md](/faq/config)                                                                                 | <https://docs.stoobly.com/faq/config>                                         | [Proxy Configuration](https://docs.stoobly.com/guides/proxy-configuration/)                                                                                                                                              |
| **Installation**                                      | `pipx install stoobly-agent`, `pipx upgrade stoobly-agent`, `docker pull stoobly/agent`                                                                                                                                                                                                | "How do I install stoobly-agent?", "How do I install Stoobly?", "How do I update stoobly-agent?", "What Python versions are supported?", "How do I verify stoobly-agent is installed?"                                                                                                                                                                                                                                                                                                                                                                    | [../../faq/installation.md](/faq/installation)                                                                     | <https://docs.stoobly.com/faq/installation>                                   | [Installation with pipx](https://docs.stoobly.com/getting-started/install-and-run/installation-with-pipx), [Installation with Docker](https://docs.stoobly.com/getting-started/install-and-run/installation-with-docker) |
| **Intercept**                                         | `intercept enable`, `intercept disable`, `intercept configure`, `intercept show`                                                                                                                                                                                                       | "How do I run Stoobly in mock mode?", "How do I enable intercept?", "How do I record requests with Stoobly?", "How do I change intercept mode?", "How do I check intercept status?"                                                                                                                                                                                                                                                                                                                                                                       | [../../faq/intercept.md](/faq/intercept)                                                                           | <https://docs.stoobly.com/faq/intercept>                                      | [How to Run the Agent](https://docs.stoobly.com/guides/how-to-run-the-agent/), [How to Record Requests](https://docs.stoobly.com/guides/how-to-record-requests/)                                                         |
| **Request**                                           | `request list`, `request replay`, `request test`, `request response show`, `request snapshot create`, `request snapshot reset`, `request snapshot diff`, `request snapshot list`                                                                                                       | "How do I list recorded requests?", "How to diagnose failed mocks or 499 responses?", "How do I replay a request?", "How do I test a request?", "How do I view a request response?", "How do I create a request snapshot?", "How do I reset a request?", "How do I diff a request snapshot?"                                                                                                                                                                                                                                                              | [../../faq/request.md](/faq/request)                                                                               | <https://docs.stoobly.com/faq/request>                                        | [How to Replay Requests](https://docs.stoobly.com/guides/how-to-replay-requests/), [How to Update Requests](https://docs.stoobly.com/guides/how-to-update-requests/)                                                     |
| **Run**                                               | `run`, `record`, `mock`, `replay`, `init`                                                                                                                                                                                                                                              | "How do I start Stoobly?", "What are Stoobly run options?", "How do I initialize Stoobly?", "How do I run Stoobly in record mode?", "How do I run Stoobly in mock mode?"                                                                                                                                                                                                                                                                                                                                                                                  | [../../faq/run.md](/faq/run)                                                                                       | <https://docs.stoobly.com/faq/run>                                            | [How to Run the Agent](https://docs.stoobly.com/guides/how-to-run-the-agent/)                                                                                                                                            |
| **Scaffold: Apply**                                   | `scaffold apply`, `scaffold apply --dry-run`, `scaffold apply --format json`                                                                                                                                                                                                           | "How do I get started with a scaffold?", "How do I make my scaffold reproducible?", "What is scaffold.yml?", "How do I apply a scaffold config?", "How do I re-create my scaffold from scratch?", "What options can go in scaffold.yml?", "Why did scaffold apply fail?", "Can I use JSON instead of YAML for scaffold.yml?"                                                                                                                                                                                                                              | [../../faq/scaffold/apply.md](/faq/scaffold/apply)                                                                 | <https://docs.stoobly.com/faq/scaffold/apply>                                 | [Applying a Scaffold Config](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/how-to-scaffold-an-app/applying-a-scaffold-config)                                                                             |
| **Scaffold**                                          | `scaffold app create`, `scaffold service create`, `scaffold workflow up`, `scaffold workflow down`, `scaffold workflow show`, `scaffold workflow rewrite`                                                                                                                              | "How do I manage E2E testing with Stoobly?", "How do I scaffold a service?", "How do I run a scaffolded workflow?", "How do I add a service to a scaffold?", "How do I create a scaffold app?", "How do I check which runtime my app uses?", "Is a workflow currently running?", "Which workflow is running?", "How do I check workflow status?", "What is the develop workflow?", "How do I redirect requests to my local dev server?", "What does scaffold workflow rewrite do?", "What workflows does Stoobly support besides record, mock, and test?" | [../../faq/scaffold/README.md](/faq/scaffold)                                                                      | <https://docs.stoobly.com/faq/scaffold>                                       | [How to Integrate E2E Testing](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/)                                                                                                                            |
| **Scaffold: Customization**                           | `scaffold workflow create`, `scaffold app create --runtime`                                                                                                                                                                                                                            | "How do I customize a scaffold?", "What is the scaffold structure?", "What is the entrypoint service?", "How do I add my app to the entrypoint?", "How do I customize docker-compose.yml?", "What files are created for each service?"                                                                                                                                                                                                                                                                                                                    | [../../faq/scaffold/customization/README.md](/faq/scaffold/customization)                                          | <https://docs.stoobly.com/faq/scaffold/customization>                         | [How to Scaffold an App](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/how-to-scaffold-an-app/)                                                                                                           |
| **Scaffold: E2E Testing**                             | `scaffold app create --plugin playwright`, `scaffold app create --plugin cypress`                                                                                                                                                                                                      | "How do I run E2E tests with Playwright?", "How do I run E2E tests with Cypress?", "How do I set up Playwright with Stoobly?", "How do I record E2E test traffic?", "How do I run E2E tests with mocked responses?", "How do I use E2E testing in CI/CD?", "Which runtime should I use in CI/CD for E2E testing?", "How do I test with Docker runtime in CI/CD?", "How do I test with local runtime in CI/CD?"                                                                                                                                            | [../../faq/scaffold/e2e-testing/README.md](/faq/scaffold/e2e-testing)                                              | <https://docs.stoobly.com/faq/scaffold/e2e-testing>                           | [How to Integrate E2E Testing](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/)                                                                                                                            |
| **Scaffold: E2E Testing: JS Client**                  | N/A                                                                                                                                                                                                                                                                                    | "How do I use the Stoobly JavaScript client library?", "What is the Stoobly JS library?", "How do I import Stoobly?", "What are the requirements for the JS library?"                                                                                                                                                                                                                                                                                                                                                                                     | [../../faq/scaffold/e2e-testing/js-client/](/faq/scaffold/e2e-testing/js-client)                                   | <https://docs.stoobly.com/faq/scaffold/e2e-testing/js-client>                 | [How to Integrate E2E Testing](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/)                                                                                                                            |
| **Scaffold: E2E Testing: JS Client: Setup**           | N/A                                                                                                                                                                                                                                                                                    | "How do I install the Stoobly JavaScript library?", "What Node version does Stoobly require?", "How do I install Stoobly with npm or yarn?"                                                                                                                                                                                                                                                                                                                                                                                                               | [../../faq/scaffold/e2e-testing/js-client/setup.md](/faq/scaffold/e2e-testing/js-client/setup)                     | <https://docs.stoobly.com/faq/scaffold/e2e-testing/js-client/setup>           | [How to Integrate E2E Testing](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/)                                                                                                                            |
| **Scaffold: E2E Testing: JS Client: Playwright**      | N/A                                                                                                                                                                                                                                                                                    | "How do I integrate Stoobly with Playwright?", "How do I use withPage() vs withContext() in Playwright?", "How do I record requests in Playwright tests?", "Why do I need withTestTitle() in Playwright?"                                                                                                                                                                                                                                                                                                                                                 | [../../faq/scaffold/e2e-testing/js-client/playwright.md](/faq/scaffold/e2e-testing/js-client/playwright)           | <https://docs.stoobly.com/faq/scaffold/e2e-testing/js-client/playwright>      | [How to Integrate E2E Testing](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/)                                                                                                                            |
| **Scaffold: E2E Testing: JS Client: Cypress**         | N/A                                                                                                                                                                                                                                                                                    | "How do I integrate Stoobly with Cypress?", "How do I apply interception in Cypress?", "How do I record requests in Cypress tests?"                                                                                                                                                                                                                                                                                                                                                                                                                       | [../../faq/scaffold/e2e-testing/js-client/cypress.md](/faq/scaffold/e2e-testing/js-client/cypress)                 | <https://docs.stoobly.com/faq/scaffold/e2e-testing/js-client/cypress>         | [How to Integrate E2E Testing](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/)                                                                                                                            |
| **Scaffold: E2E Testing: JS Client: Configuration**   | N/A                                                                                                                                                                                                                                                                                    | "How do I configure which URLs get intercepted?", "How do I change scenarios dynamically?", "What record policies are available?", "How do I stop recording?", "How do I use sessions?"                                                                                                                                                                                                                                                                                                                                                                   | [../../faq/scaffold/e2e-testing/js-client/configuration.md](/faq/scaffold/e2e-testing/js-client/configuration)     | <https://docs.stoobly.com/faq/scaffold/e2e-testing/js-client/configuration>   | [How to Integrate E2E Testing](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/)                                                                                                                            |
| **Scaffold: E2E Testing: JS Client: npm Scripts**     | `scaffold workflow up --detached`, `scaffold workflow down`                                                                                                                                                                                                                            | "How do I run stoobly-agent workflows from npm scripts?", "Will the scaffold test workflow run my Playwright/Cypress tests automatically?", "How do I avoid manually starting and stopping the Stoobly workflow around my tests?", "How do I bring the workflow up, run tests, and tear it down in one command?", "Why do my scripts need --detached?", "How do I make these scripts work in CI?"                                                                                                                                                         | [../../faq/scaffold/e2e-testing/js-client/npm-scripts.md](/faq/scaffold/e2e-testing/js-client/npm-scripts)         | <https://docs.stoobly.com/faq/scaffold/e2e-testing/js-client/npm-scripts>     | [How to Integrate E2E Testing](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/)                                                                                                                            |
| **Scaffold: E2E Testing: JS Client: Troubleshooting** | N/A                                                                                                                                                                                                                                                                                    | "Why isn't Stoobly intercepting requests?", "What's a complete Playwright example with recording and mocking?", "What's a complete Cypress example?", "What methods does the interceptor have?", "What constants are available?"                                                                                                                                                                                                                                                                                                                          | [../../faq/scaffold/e2e-testing/js-client/troubleshooting.md](/faq/scaffold/e2e-testing/js-client/troubleshooting) | <https://docs.stoobly.com/faq/scaffold/e2e-testing/js-client/troubleshooting> | [How to Integrate E2E Testing](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/)                                                                                                                            |
| **Scaffold: Runtime**                                 | `scaffold app create --runtime`, `scaffold workflow up`, `make -f .stoobly/services/.Makefile`                                                                                                                                                                                         | "What's the difference between Docker and local runtime?", "Which runtime should I choose?", "How do I switch between runtimes?", "How do I use Docker runtime?", "How do I use local runtime?", "What are the requirements for Docker runtime?", "What are the requirements for local runtime?", "Can I use both runtimes together?", "How do I validate my service configuration?", "What do I do if a workflow fails to start?", "How do I troubleshoot scaffold issues?"                                                                              | [../../faq/scaffold/runtime/README.md](/faq/scaffold/runtime)                                                      | <https://docs.stoobly.com/faq/scaffold/runtime>                               | [How to Integrate E2E Testing](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/)                                                                                                                            |
| **Scenario**                                          | `scenario create`, `scenario list`, `scenario replay`, `scenario test`, `scenario snapshot create`, `scenario snapshot reset`, `scenario snapshot diff`, `scenario snapshot list`                                                                                                      | "How do I snapshot a scenario?", "How do I list scenarios?", "How do I create a scenario?", "How do I replay a scenario?", "How do I test a scenario?", "How do I reset a scenario?", "How do I diff a scenario snapshot?"                                                                                                                                                                                                                                                                                                                                | [../../faq/scenario.md](/faq/scenario)                                                                             | <https://docs.stoobly.com/faq/scenario>                                       | [How to Record Requests](https://docs.stoobly.com/guides/how-to-record-requests/how-to-create-scenarios/), [How to Update Scenarios](https://docs.stoobly.com/guides/how-to-update-requests/how-to-update-scenarios/)    |
| **Snapshot**                                          | `snapshot list`, `snapshot apply`, `snapshot reset`, `snapshot copy`, `request snapshot create`, `request snapshot reset`, `request snapshot diff`, `request snapshot list`, `scenario snapshot create`, `scenario snapshot reset`, `scenario snapshot diff`, `scenario snapshot list` | "How do I use snapshots?", "How can I diff snapshots?", "How do I apply snapshots?", "How do I share snapshots?", "How do I create a snapshot?", "How do I reset a snapshot?", "How do I reset all snapshots?", "What does --hard do?", "How do I compare snapshots?", "How do I list request snapshots?", "How do I list scenario snapshots?", "How do I reset requests and scenarios at once?"                                                                                                                                                          | [../../faq/snapshot.md](/faq/snapshot)                                                                             | <https://docs.stoobly.com/faq/snapshot>                                       | [How to Snapshot Requests](https://docs.stoobly.com/guides/how-to-mock-apis/how-to-snapshot-requests/)                                                                                                                   |
| **API Testing**                                       | `request test`, `scenario test`                                                                                                                                                                                                                                                        | "How do I test a request?", "How do I test a scenario?", "What test strategies are available?", "How do I use diff testing?", "How do I use contract testing?", "How do I run tests in CI/CD?", "How do I debug failing tests?"                                                                                                                                                                                                                                                                                                                           | [../../faq/api-testing.md](/faq/api-testing)                                                                       | <https://docs.stoobly.com/faq/api-testing>                                    | [How to Replay Requests](https://docs.stoobly.com/guides/how-to-replay-requests/)                                                                                                                                        |

### Skills Table

Skills are multi-step troubleshooting workflows. When a matched question maps to a skill, read the skill page and follow its instructions in order.

| Skill                     | Primary Commands                                                                                    | Example Questions                                                                                                                                                                                                                    | Local Docs                                                                                                                   | Remote Docs                                                                                                    | Related Guides                                                                                                                                                                                                |
| ------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **JS Client**             | `scaffold workflow up`, `scaffold workflow down`, `scaffold describe`, `scaffold request logs list` | "How do I integrate Stoobly with Playwright?", "How do I add Stoobly to Cypress?", "How do I set up the JS client?", "How do I use the stoobly npm package?", "How do I record API traffic from my tests?"                           | [Skills/stoobly-js-client.md](/getting-started/configuring-an-ai-assistant/skills/stoobly-js-client)                         | <https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/Skills/stoobly-js-client.md>             | [JS Client FAQ](https://docs.stoobly.com/faq/scaffold/e2e-testing/js-client/), [Integrating the JavaScript Client](https://docs.stoobly.com/getting-started/integrating-the-javascript-client)                |
| **Scaffold Create**       | `scaffold apply`, `scaffold app create`, `scaffold service create`, `scaffold workflow up`          | "How do I get started with Stoobly?", "How do I bootstrap a scaffold app?", "How do I create a new Stoobly scaffold?", "How do I add services to my scaffold app?", "How do I run my first Stoobly workflow?"                        | [Skills/stoobly-scaffold-create.md](/getting-started/configuring-an-ai-assistant/skills/stoobly-scaffold-create)             | <https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/Skills/stoobly-scaffold-create.md>       | [How to Integrate E2E Testing](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/), [How to Scaffold an App](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/how-to-scaffold-an-app/) |
| **Stoobly**               | `stoobly-agent --version`, `scaffold describe`                                                      | "Help me with Stoobly", "I want to mock my APIs", "Set up E2E testing", "Where do I start with Stoobly?", "Which Stoobly skill should I use?"                                                                                        | [Skills/stoobly.md](/getting-started/configuring-an-ai-assistant/skills/stoobly)                                             | <https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/Skills/stoobly.md>                       | [Introduction](https://docs.stoobly.com/), [Use Cases](https://docs.stoobly.com/use-cases/)                                                                                                                   |
| **Triage**                | `scaffold request logs list`, `scaffold workflow logs`, `request logs list`                         | "Stoobly isn't working, what's wrong?", "Why am I getting 499 errors?", "Why is Stoobly not intercepting my traffic?", "How do I fix HTTPS certificate errors?", "Stoobly won't start, port conflict"                                | [Skills/stoobly-triage.md](/getting-started/configuring-an-ai-assistant/skills/stoobly-triage)                               | <https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/Skills/stoobly-triage.md>                | [Troubleshooting Mock APIs](https://docs.stoobly.com/guides/how-to-mock-apis/troubleshooting), [CA Cert FAQ](https://docs.stoobly.com/faq/ca-cert)                                                            |
| **Troubleshoot E2E Test** | `scaffold request logs list`, `request list`, `request response show`                               | "How do I troubleshoot E2E test failures?", "Why did my E2E test fail?", "How do I debug scaffold test failures?", "How do I cross-reference Playwright logs with Stoobly?", "How do I view scenario requests after a test failure?" | [Skills/stoobly-troubleshoot-e2e-test.md](/getting-started/configuring-an-ai-assistant/skills/stoobly-troubleshoot-e2e-test) | <https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/Skills/stoobly-troubleshoot-e2e-test.md> | [How to Integrate E2E Testing](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/), [Troubleshooting Mock APIs](https://docs.stoobly.com/guides/how-to-mock-apis/troubleshooting)                  |
| **Update Request**        | `request update`, `request response update`, `request response show`, `request snapshot create`     | "How do I update a request?", "How do I update a response?", "How do I change a mock response body?", "How do I fix an outdated recorded response?", "How do I update request headers or status code?"                               | [Skills/stoobly-update-request.md](/getting-started/configuring-an-ai-assistant/skills/stoobly-update-request)               | <https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/Skills/stoobly-update-request.md>        | [How to Update Requests](https://docs.stoobly.com/guides/how-to-update-requests/), [Request FAQ](https://docs.stoobly.com/faq/request), [Snapshot FAQ](https://docs.stoobly.com/faq/snapshot)                 |


# Skills

Copyable skill definitions for AI assistants. Each page uses skill format (YAML frontmatter with `name` and `description`, plus step-by-step instructions) so you can paste the full contents into your assistant's skill file.

## Available skills

| Skill                 | Page                                                                                                                  |
| --------------------- | --------------------------------------------------------------------------------------------------------------------- |
| JS Client             | [stoobly-js-client.md](/getting-started/configuring-an-ai-assistant/skills/stoobly-js-client)                         |
| Scaffold Create       | [stoobly-scaffold-create.md](/getting-started/configuring-an-ai-assistant/skills/stoobly-scaffold-create)             |
| Stoobly               | [stoobly.md](/getting-started/configuring-an-ai-assistant/skills/stoobly)                                             |
| Triage                | [stoobly-triage.md](/getting-started/configuring-an-ai-assistant/skills/stoobly-triage)                               |
| Troubleshoot E2E Test | [stoobly-troubleshoot-e2e-test.md](/getting-started/configuring-an-ai-assistant/skills/stoobly-troubleshoot-e2e-test) |
| Update Request        | [stoobly-update-request.md](/getting-started/configuring-an-ai-assistant/skills/stoobly-update-request)               |

**Stoobly** is the entry point — it detects your setup and routes to the right skill below, so install it first if you're not sure which skill you need.

## How to use

1. Open the skill page.
2. Copy the entire file contents (including the frontmatter at the top).
3. Paste into your assistant's skill location — for example `.cursor/skills/stoobly-troubleshoot-e2e-test/SKILL.md` in Cursor or an equivalent path in Claude Code.

Skills are also listed in the [LLM Rules index](/getting-started/configuring-an-ai-assistant/llm-rules) so assistants reading Stoobly docs can find them automatically.


# JS Client

````markdown
---
name: stoobly-js-client
description: Wires the Stoobly JavaScript client (npm `stoobly`) into an E2E test
  suite — interceptor setup, scenarios, npm scripts, and a verification run. Has
  dedicated support for Playwright and Cypress today, plus a generic interceptor
  for other frameworks (Puppeteer, WebdriverIO, TestCafe, vanilla JS, etc.). Use
  when the user wants to integrate Stoobly with their E2E tests, add Stoobly to
  Playwright/Cypress/another test framework, set up the JS client, use the
  `stoobly` npm package, or record/mock API traffic from their test code.
---

# JS Client Integration

You are helping the user wire the Stoobly JavaScript client library into their E2E test suite. This skill **writes code** into the user's repo (interceptor wiring, npm scripts) after showing exactly what will change and getting confirmation — it does not just explain the docs.

The library has dedicated, framework-tailored interceptors for **Playwright** and **Cypress** today — these are the popular examples covered in detail below, not an exhaustive list. Any other framework (Puppeteer, WebdriverIO, TestCafe, Nightwatch, Selenium, a custom runner, or plain Node/browser code) works through the generic `interceptor()` method; more framework-specific interceptors may be added over time, so re-check `stoobly/package.json`'s exports if a framework the user names isn't listed here.

If the test suite is already wired and a test is failing, use the Troubleshoot E2E Test skill instead — this skill is for first-time authoring, not debugging an existing integration.

## Step 1: Detect repo state (read-only)

Read `package.json` to determine:

- **E2E framework**: check `dependencies`/`devDependencies` for `@playwright/test`, `cypress`, and other common runners (`puppeteer`, `webdriverio`, `testcafe`, `nightwatch`, `selenium-webdriver`, etc.). Playwright and Cypress get dedicated wiring (Step 5); anything else uses the generic interceptor.
- **Existing `stoobly` dependency**: already installed?
- **Package manager**: infer from the lockfile present (`package-lock.json` → npm, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm).
- **Module system**: `"type": "module"` (ESM) vs CommonJS.

Also check for a framework config file (`playwright.config.*`, `cypress.config.*`, or equivalent), a `tsconfig.json` (determines whether wiring should be TypeScript or JavaScript), and existing test/support directory layout so new files match it.

Run `node --version` and confirm it's 18 or higher — the library requires it.

If no framework is detected, ask the user which one they're using rather than guessing. If more than one is present, ask which they want wired.

## Step 2: Check prerequisites and hand off if needed

1. Run `stoobly-agent --version`. If not found, stop here — the `stoobly` npm package is a **client library**, not a CLI; it controls interception but a separate `stoobly-agent` install runs the workflows alongside it. Point the user at installation: `https://docs.stoobly.com/faq/installation`.
2. Check whether `.stoobly/services/.config.yml` exists in the current directory (existence check only — do not read its contents; see the hard constraint on scaffold state). The JS client needs a running `stoobly-agent` scaffold workflow to talk to. If it doesn't exist, tell the user and offer the Scaffold Create skill — do not duplicate that flow here.
3. If it exists, run `stoobly-agent scaffold describe` to get `app_dir_path` and `context_dir_path`. Note whether `package.json` lives at `app_dir_path` or elsewhere (monorepo) — this determines whether npm scripts need `--app-dir-path`/`--context-dir-path` in Step 6.

## Step 3: Read the docs

Read local files under `.stoobly/docs/faq/scaffold/e2e-testing/js-client/`, falling back to `https://docs.stoobly.com/faq/scaffold/e2e-testing/js-client/<page>.md` if the local path doesn't exist:

- `setup.md` — installation, imports, `Stoobly` constructor
- `playwright.md` or `cypress.md` — if one of these applies; for any other framework, rely on `configuration.md` and the generic `interceptor()` reference in `setup.md`/`troubleshooting.md` instead, since there's no dedicated per-framework doc yet
- `configuration.md` — URL patterns, scenarios, sessions, record settings, intercept mode control (applies to every framework, dedicated or generic)
- `npm-scripts.md` — wrapping workflow commands in `package.json`

## Step 4: Ask configuration questions (single message)

1. **URLs to intercept** — which API base URL(s) should Stoobly intercept? (string or regex; multiple allowed)
2. **Scope** (Playwright only) — `withContext()` (recommended: covers pages created mid-test, extensions, service workers) or `withPage()` (single-page tests only)? Not applicable to other frameworks.
3. **Scenario naming** — confirm deriving scenario names from a hierarchical test path where the framework exposes one (`testInfo.titlePath.join(' > ')` in Playwright, `this.test.titlePath().join(' > ')` in Cypress) rather than managing a `scenarioKey` by hand. For frameworks without an equivalent, ask what should identify a scenario (suite/test name, a fixed string, etc.). This is the recommended default; only ask further if they want something else.
4. **`context.request` usage** (Playwright only) — do any tests call `context.request` / use Playwright's `APIRequestContext` directly? These aren't covered by `context.route()` and need extra header wiring.
5. **Mode control** — confirm using the `STOOBLY_INTERCEPT_MODE` environment variable (defaults to `mock`, set to `record` to capture) instead of hardcoding the mode.

## Step 5: Install and write the wiring

Install as a dev dependency with the detected package manager:

```bash
npm install stoobly --save-dev
# or
yarn add -D stoobly
```

Then show the **full proposed file contents** (new files) or diffs (edits to existing files) for the following, and ask "Ready to write these? (yes / let me review first)" before writing anything.

Use the dedicated Playwright or Cypress wiring below when one of those applies; otherwise use the generic interceptor further down.

### Playwright

Write a fixture module (path matching the repo's existing test layout, e.g. `tests/fixtures/stoobly.ts` or `.js`) that exports an extended `test`:

- `base.extend({ stooblyInterceptor: [async ({ context, page }, use, testInfo) => { ... }, { auto: true }] })`. `auto: true` is required so interception starts before any other fixture makes a network call.
- Inside the fixture: `const stoobly = new Stoobly()` (defaults to `http://localhost:4200`), then `stoobly.playwrightInterceptor({ urls, scenarioName, mode })`.
- `await interceptor.withContext(context).enable()` (or `.withPage(page)` per the Step 4 answer), then `interceptor.withTestTitle(testInfo.title)`.
- Mode: read `process.env.STOOBLY_INTERCEPT_MODE`, default `'mock'`, map to `InterceptMode` from `stoobly/constants`.
- If the user uses `context.request`: after `enable()`, add `await context.setExtraHTTPHeaders((interceptor as any).headers)` with a comment that `context.route()` does not intercept `APIRequestContext` calls, so headers must be copied onto the context explicitly.

Tell the user to import `test` from this fixture module instead of `@playwright/test` in their spec files. Offer to update one spec file as a worked example rather than rewriting the whole suite unasked.

### Cypress

Wire into `cypress/support/e2e.js` or `.ts` (create if it doesn't exist, otherwise append):

- Module-level: `const interceptor = stoobly.cypressInterceptor({ urls, mode })`.
- `beforeEach(function () { ... })` — must use the `function()` form, not an arrow function, so `this.test.titlePath()` is available.
- Inside: derive `scenarioName` from `this.test.titlePath().join(' > ')`, call `interceptor.withScenarioName(scenarioName)`, then `interceptor.enable()`.
- Comment explaining why `enable()` must run in `beforeEach`: Cypress clears all `cy.intercept`s between tests.
- If the repo has any synchronous `XMLHttpRequest` calls, flag that they'll hang Cypress with the interceptor active and should be converted to async/`cy.request`.

### Other frameworks (generic interceptor)

For any framework without a dedicated method — Puppeteer, WebdriverIO, TestCafe, Nightwatch, Selenium, a custom runner, or plain Node/browser code — use `stoobly.interceptor(settings)`. It patches `fetch`/`XMLHttpRequest` directly rather than hooking into a specific framework's routing layer, so it works anywhere JS requests originate, but you're responsible for calling `enable()`/`disable()` at the right point in that framework's lifecycle (equivalent of Playwright's fixture or Cypress's `beforeEach`) since there's no framework-specific auto-wiring to lean on.

- `const stoobly = new Stoobly()`, then `const interceptor = stoobly.interceptor({ scenarioName, urls, mode })`.
- Call `interceptor.enable()` wherever the framework runs setup before each test (its equivalent of `beforeEach`/a fixture/a hook), and `interceptor.disable()` in the matching teardown if the framework reuses the process across tests and you need a clean slate between them.
- Set `withTestTitle()` from whatever the framework exposes as the current test name, if anything.
- Because there's no built-in per-page/per-context scoping, verify network calls actually get intercepted in Step 7 before assuming this works — frameworks that run tests in separate processes/workers (rather than a shared Node process) may need the interceptor set up per worker.

### TypeScript

If `tsconfig.json` exists, mention that types are available from `stoobly/types`, and check `compilerOptions.types` includes `"stoobly"`, plus `moduleResolution` and `esModuleInterop` are set (see Troubleshooting doc) — fix if missing.

## Step 6: Add npm scripts

Per `npm-scripts.md`, add `stoobly:<workflow>` / `stoobly:<workflow>:down` script pairs for the workflow(s) the user runs (typically `mock`, and `record` if they'll capture traffic from tests), plus one combined script that brings the workflow up, runs tests, captures the exit code, and tears down regardless of pass/fail:

```json
{
  "scripts": {
    "stoobly:mock": "stoobly-agent scaffold workflow up mock --detached",
    "stoobly:mock:down": "stoobly-agent scaffold workflow down mock",
    "test:mock": "npm run stoobly:mock && npx playwright test; RESULT=$?; npm run stoobly:mock:down; exit $RESULT"
  }
}
```

(Swap `npx playwright test` for the repo's actual test command — `npx cypress run`, `npx testcafe`, or whatever the framework detected in Step 1 uses.)

Apply these footguns from the docs:

- **Always pass `--detached`** on `workflow up`. On Docker runtime, `up` attaches to logs and never returns without it, hanging the script before tests ever run; on local runtime it's a no-op. Passing it always keeps one script correct on both runtimes.
- **Capture the exit code before teardown.** Chaining with `&&` alone stops at the first failure and never tears down; chaining with `;` alone lets `down`'s exit code mask a test failure. Use the `RESULT=$?` pattern above so a failing test still fails the npm script (important for CI).
- **Use `cross-env`** for `STOOBLY_INTERCEPT_MODE=record` if the project needs to run on Windows — a bare env-var prefix only works on POSIX shells.
- **Pass `--app-dir-path`/`--context-dir-path`** on both `up` and `down` if Step 2 found `package.json` isn't at the scaffold app root (monorepo), using the same values on both so `down` can find what `up` started.

## Step 7: Verify

Don't assume the wiring works — run it:

1. Bring up the record workflow and run the suite once with `STOOBLY_INTERCEPT_MODE=record` to capture traffic.
2. Bring up the mock workflow and run the suite again with the default (`mock`) mode.
3. From `app_dir_path`, run `stoobly-agent scaffold request logs list <workflow>` and confirm the expected requests appear.

If nothing appears in the logs, interception isn't happening — check the URL patterns match, that `enable()` actually runs at the right point (fixture `auto: true` / Cypress `beforeEach` / the equivalent hook for another framework), and that `stoobly-agent` is up. If requests appear with **status 499**, they were intercepted but had no matching recording — hand off to the Troubleshoot E2E Test skill for that diagnosis.

Report the verification result plainly, including full output if either run failed — don't report success unless the logs actually confirm interception.

## Step 8: Surface next steps

End with:

> **Next steps:**
> - See [How to Record Requests](../../../guides/how-to-record-requests/) to capture more traffic, and [How to Mock APIs](../../../guides/how-to-mock-apis/) to serve it back without hitting real APIs.
> - See [Snapshot](../../../faq/snapshot.md) to commit recordings to Git so teammates get the same mocks.
> - Use the Troubleshoot E2E Test skill if a test starts failing against mocks later.
> - For CI, install `stoobly-agent` via `pipx`, install the CA cert as a separate setup step, and pass `--ca-certs-install-confirm y --hostname-install-confirm y` to `workflow up` so it doesn't hang on interactive prompts — see the CI/CD section of the npm scripts doc.
>
> Docs: https://docs.stoobly.com/faq/scaffold/e2e-testing/js-client

## Reference documentation

| Topic | Doc |
| ----- | --- |
| Installation & imports | [Setup](../../../faq/scaffold/e2e-testing/js-client/setup.md) |
| Playwright integration | [Playwright](../../../faq/scaffold/e2e-testing/js-client/playwright.md) |
| Cypress integration | [Cypress](../../../faq/scaffold/e2e-testing/js-client/cypress.md) |
| URL/scenario/session/record configuration | [Configuration](../../../faq/scaffold/e2e-testing/js-client/configuration.md) |
| npm scripts & CI | [npm Scripts](../../../faq/scaffold/e2e-testing/js-client/npm-scripts.md) |
| Debugging & complete examples | [Troubleshooting](../../../faq/scaffold/e2e-testing/js-client/troubleshooting.md) |
| Concepts (intercept modes, scenarios, sessions, context) | [Integrating the JavaScript Client](../../../getting-started/integrating-the-javascript-client.md) |
| Full API reference | [TypeDoc reference](https://stoobly.github.io/stoobly-js/) |
| Scaffold setup | [Scaffold Create](stoobly-scaffold-create.md) |
| Debug a failing E2E test | [Troubleshoot E2E Test](stoobly-troubleshoot-e2e-test.md) |
| Share recordings with teammates | [Snapshot FAQ](../../../faq/snapshot.md) |
````


# Scaffold Create

````markdown
---
name: stoobly-scaffold-create
description: Bootstraps a new Stoobly scaffold app and services. Use when the user
  wants to get started with Stoobly, create a scaffold app, add services, or run
  their first workflow.
---

# Scaffold Create

You are helping the user bootstrap a Stoobly scaffold application.

## Step 1: Detect existing state

Check if `.stoobly/services/.config.yml` exists in the current directory.

- If it exists, read it and report the user's current config (app name, runtime, proxy mode). Then ask: "You already have a scaffold app. Do you want to add more services, or start fresh?"
- If it does not exist, proceed to Step 2.

## Step 2: Read the docs

Read the local file `.stoobly/docs/faq/scaffold/README.md` to get current command syntax. If it doesn't exist, fetch `https://docs.stoobly.com/faq/scaffold.md` instead.

## Step 3: Ask the user these questions (ask all at once, in a single message)

1. **App name**: What do you want to call this scaffold app? (e.g., `my-app`)
2. **Runtime**: Local (faster, no Docker required) or Docker (recommended for teams and CI/CD)?
3. **Proxy mode**: Forward proxy (your app/tests explicitly use `http://localhost:8080` as a proxy) or Reverse proxy (traffic routed transparently by hostname — better for browser-based apps)?
4. **E2E testing**: Are you setting up E2E tests? If so, which framework — Playwright, Cypress, both, or neither?
5. **Services**: List the backend service(s) you want to mock. For each, provide:
   - A short name (e.g., `api`, `payments-service`)
   - The hostname of the real service (e.g., `api.example.com` or `localhost`)
   - The port (e.g., `3000`, `443`)
   - The scheme (`http` or `https`)

## Step 4: Create scaffold config and apply

Write a declarative scaffold config at **`.stoobly/scaffold.yml`** (create the `.stoobly/` directory if it does not exist). This file is consumed by `stoobly-agent scaffold apply` and maps 1:1 to scaffold CLI commands.

Use this structure:

```yaml
version: 1
commands:
  - resource: app
    action: create
    options:
      app_name: <app-name>
      runtime: <local|docker>
      proxy_mode: <forward|reverse>
      # plugin: [playwright]   # uncomment if E2E framework selected

  - resource: service
    action: create
    options:
      service_name: <service-name>
      hostname: <hostname>
      scheme: <http|https>
      port: <port>

  # Add one service block per service. Repeat as needed.

  # Optional reference — uncomment to create custom workflows later:
  # - resource: workflow
  #   action: create
  #   options:
  #     workflow_name: ci
  #     template: mock
  #     service: [<service-name>]
```

Rules for the YAML file (full reference: `.stoobly/docs/faq/scaffold/apply.md`, or `https://docs.stoobly.com/faq/scaffold/apply.md` if that file doesn't exist):

- Top-level `version` must be the integer `1` (not the string `"1"`).
- `commands` is a non-empty ordered list; the whole config is validated up front, then steps run sequentially and stop on the first failure — steps already applied are not rolled back.
- `resource`/`action` pairs are limited to: `app create`; `service create|list|show|delete|update`; `workflow create|copy|show|up|down|logs|mkcert|rewrite|filter|validate`; `hostname install|uninstall`.
- Option keys use **snake_case** matching the CLI flag (e.g., `app_name`, `proxy_mode`, `service_name`). An unknown option key for the target command is a validation error.
- Flags are booleans (`true` / `false`).
- Multi-value options (e.g., `plugin`, `service`) use YAML lists; a bare scalar is also accepted as one value.
- Omit `app_dir_path` to scaffold in the current working directory (typical single-repo setup).
- Only these keys are path-expanded: `app_dir_path`, `context_dir_path`, `script_path`, `ca_certs_dir_path`, `certs_dir_path`, `docker_socket_path`. Relative values resolve against `.stoobly/` (the config file's directory), not the cwd. Apply never creates directories.
- `--format json` is also supported if the user prefers JSON over YAML.

Show the generated YAML to the user and ask: "Ready to apply this? (yes / let me review first)"

Once confirmed:

1. Write `.stoobly/scaffold.yml` to disk
2. Validate with a dry run: `stoobly-agent scaffold apply .stoobly/scaffold.yml --dry-run` — note this checks the config's schema but does not exercise every check a real apply does (e.g. required directories existing)
3. If dry run succeeds, apply for real: `stoobly-agent scaffold apply .stoobly/scaffold.yml`

After execution, report whether it succeeded or failed. If it fails, stop and show the full error output before asking how to proceed.

Tell the user they can re-run or share this setup anytime with `stoobly-agent scaffold apply .stoobly/scaffold.yml`.

## Step 5: Surface next steps

After all commands succeed, tell the user:

- How to route traffic through the proxy (proxy env vars for forward proxy, or hostname setup for reverse proxy)
- If recording HTTPS, remind them the CA cert was installed (or how to install it manually if skipped)
- Offer to immediately start the record workflow

End with:

> **Next steps:**
> - Now that your Stoobly scaffold is created, you can now run workflows! See [How to Run a Workflow](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/how-to-run-a-workflow)
> - Or to further customize a workflow, see [Customizing a Workflow](https://docs.stoobly.com/guides/how-to-integrate-e2e-testing/how-to-scaffold-an-app/customizing-a-workflow)
>
> Docs: https://docs.stoobly.com/faq/scaffold
> 
> Runtime comparison: https://docs.stoobly.com/faq/scaffold/runtime
````


# Stoobly

```markdown
---
name: stoobly
description: Entry point for anything Stoobly — API recording, mocking, E2E testing, snapshots,
  scaffolds, and troubleshooting. Use when the user wants help with Stoobly but hasn't named a
  specific workflow ("help me with Stoobly", "I want to mock my APIs", "set up E2E testing"), or
  when it's unclear which Stoobly skill applies. Routes to the specific stoobly-* skill. If the
  user has already named the workflow, use that skill directly instead.
---

# Stoobly

You are the front door for Stoobly — a router that figures out what the user wants to do and hands
off to the right skill. You do not do the work yourself; you pick a destination and follow it.

## Step 1: Detect existing state (read-only)

Do **not** `cat` or read `.config.yml` or any scaffold directory file directly to determine state —
always use the CLI.

- Check `stoobly-agent` is installed: run `stoobly-agent --version`. If it's not found, skip
  straight to Step 5 (docs fallback) using the **Installation** row of the Index table.
- Check whether `.stoobly/services/.config.yml` exists in the current directory to tell scaffold
  from standalone (existence check only — do not read its contents).
- If it exists, run `stoobly-agent scaffold describe` to get the app/context info.

Report the detected setup in one line (e.g. "You have a scaffold app configured" / "No scaffold
detected — you're running standalone"). This determines which menu you show in Step 3: no config
file → Menu A; config file exists → Menu B.

## Step 2: Skip the menu if intent is already clear

If the user's request already maps clearly to one row in the table below, skip the menu — say
which skill you're using and why in one line, then jump to Step 4.

## Step 3: Ask what the user wants to do

If intent isn't already clear, ask a single message using the menu that matches Step 1's
detection. Post the full numbered menu below as **message text** — don't rely on a choice tool
to display it, since those commonly cap at four options and would silently drop the rest.
Then, if a choice tool is available, use one to capture the answer — it's a nicer experience
than plain text. Put the four most likely items (by the menu's own ordering) on it as buttons,
and make its question text say any item can be reached by typing it (e.g. via an "Other"
option) — never present fewer than all eight as reachable.

**Menu B — scaffold detected** (day-to-day loop first):

> What do you want to do with Stoobly?
> 1. **Something's broken** — errors, 499s, certs, won't start, traffic not intercepted, or a failing E2E test
> 2. **Record, mock, or test API traffic** — the day-to-day intercept loop
> 3. **Fix a wrong or outdated request/response** — one specific request is bad
> 4. **Scenarios, snapshots, and sharing** — refresh recordings after an API change, commit/restore via Git
> 5. **Manage an existing scaffold** — add/remove/inspect services, logs, hostnames, reset (also pick this for standalone setups: agent config, intercept settings, restarts)
> 6. **Wire Stoobly into my JS test code** — Playwright, Cypress, or another E2E framework
> 7. **Set up another scaffold app**
> 8. **Just a question** — how something works, concepts, install, CLI syntax

**Menu A — no scaffold detected** (onboarding first, same eight intents reordered):

> What do you want to do with Stoobly?
> 1. **Set up Stoobly for the first time** — create a scaffold app and services
> 2. **Wire Stoobly into my JS test code** — Playwright, Cypress, or another E2E framework
> 3. **Record, mock, or test API traffic** — the day-to-day intercept loop
> 4. **Something's broken** — errors, 499s, certs, won't start, traffic not intercepted, or a failing E2E test
> 5. **Fix a wrong or outdated request/response** — one specific request is bad
> 6. **Scenarios, snapshots, and sharing** — refresh recordings after an API change, commit/restore via Git
> 7. **Manage an existing scaffold** — add/remove/inspect services, logs, hostnames, reset (also pick this for standalone setups: agent config, intercept settings, restarts)
> 8. **Just a question** — how something works, concepts, install, CLI syntax

If the user picks **Something's broken** and it's not already clear whether this is happening
inside a failing E2E test, ask that one clarifying question directly instead of another numbered
menu (see the first disambiguation rule below).

## Step 4: Route

Route by the menu **label** the user picked, not its number — the two menus number the same
labels differently. Not every label has a dedicated skill; labels whose destination is **Docs
fallback** in the table below are handled by Step 5 instead.

| Choice | Destination |
|---|---|
| Something's broken — general usage | `stoobly-triage` |
| Something's broken — inside a failing E2E test | `stoobly-troubleshoot-e2e-test` |
| Set up Stoobly / set up another scaffold app | `stoobly-scaffold-create` |
| Wire Stoobly into my JS test code | `stoobly-js-client` |
| Fix a wrong or outdated request/response | `stoobly-update-request` |
| Record, mock, or test API traffic | Docs fallback — go to Step 5, start at the **Intercept**, **Run**, or **API Testing** row |
| Scenarios, snapshots, and sharing | Docs fallback — go to Step 5, start at the **Scenario** or **Snapshot** row |
| Manage an existing scaffold | Docs fallback — go to Step 5, start at the **Scaffold**, **Scaffold: Runtime**, or **Config** row |
| Just a question | Docs fallback — go to Step 5, match the Index normally |

Disambiguation rules:

- **499s or wrong/stale responses**: if it's happening **inside a failing scaffolded E2E test**
  (Playwright, Cypress, etc.), route to `stoobly-troubleshoot-e2e-test`. Otherwise (general usage,
  outside a test run), route to `stoobly-triage`.
- **One request/response wrong**: `stoobly-update-request`. **A scenario stale after an API
  change**: docs fallback (Scenario / Snapshot rows of the Index table).
- **Authoring vs debugging the JS client**: setting up the Playwright/Cypress interceptor for the
  first time → `stoobly-js-client`. A test that's already wired but failing →
  `stoobly-troubleshoot-e2e-test`.
- **First-time setup that mentions Playwright/Cypress**: no scaffold yet → `stoobly-scaffold-create`
  (it supports `--plugin playwright`/`--plugin cypress`). A scaffold already exists and only the
  test wiring is missing → `stoobly-js-client`.

Once you've picked a skill, announce it in one line (e.g. "Using `stoobly-triage` — it covers cert
errors and broken traffic interception"), then read that skill's instructions and follow them in
order starting from its own Step 1. If the skill isn't installed locally, read it from this docs
site instead — local path `getting-started/configuring-an-ai-assistant/Skills/<name>.md` under
wherever the docs were cloned, or
`https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/Skills/<name>` as a fallback.
Do not re-ask questions the sub-skill is about to ask, and do not route again mid-flow — once
handed off, the sub-skill owns the rest of the conversation. If the request genuinely spans two
skills, pick whichever is blocking right now and mention the other in your next-steps at the end.

## Step 5: Docs fallback (no skill fits)

Use this whenever Step 4 pointed here — no dedicated skill for the chosen task, no skill matches
the question, or `stoobly-agent` isn't installed.

Read `.stoobly/docs/getting-started/configuring-an-ai-assistant/llm-rules.md` (fallback:
`https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/llm-rules.md`) and follow its
own routing workflow (§5 Index). If Step 4 named an Index row for this branch, start there instead
of re-matching from scratch; otherwise match the question against the Index table's "Example
Questions" column. Read the matched Local Doc, and answer using the Example Answer Template —
complete CLI commands prefixed `stoobly-agent`, and a link to the relevant `docs.stoobly.com` page.
Do not answer from memory.

## Step 6: Surface next steps

If you routed to a skill, its own next-steps apply — don't duplicate them. If you answered from
docs (Step 5), close with:

> Typical Stoobly workflow: scaffold a new app, record traffic, mock it, test against it, then
> update recordings as the API changes (see the docs for exact commands).
> Something broken? Use the Triage skill. Ask again any time to pick a different task.
>
> Docs: https://docs.stoobly.com

## Reference documentation

| Topic | Doc |
| ----- | --- |
| Set up Stoobly for the first time | [Scaffold Create](stoobly-scaffold-create.md) |
| Something's broken (general usage) | [Triage](stoobly-triage.md) |
| Something's broken (inside an E2E test) | [Troubleshoot E2E Test](stoobly-troubleshoot-e2e-test.md) |
| Wire Stoobly into JS test code | [JS Client](stoobly-js-client.md) |
| Fix a wrong or outdated request/response | [Update Request](stoobly-update-request.md) |
| Full routing index for everything else | [LLM Rules](../llm-rules.md) |
```


# Triage

````markdown
---
name: stoobly-triage
description: Diagnoses and fixes general Stoobly setup and runtime problems. Use when the
  user has HTTPS/certificate errors, traffic that isn't being intercepted, port
  conflicts, Stoobly failing to start, standalone (non-scaffold) issues, or wants a
  broad "something's broken" triage — including 499s and wrong responses outside of a
  test run. If the problem is a failing scaffolded E2E test (Playwright/Cypress), use
  stoobly-troubleshoot-e2e-test instead.
---

# Triage

You are helping the user diagnose and fix a problem with their Stoobly setup or usage.

## Step 1: Detect existing state

Check if `.stoobly/services/.config.yml` exists in the current directory.

- If it exists, read it and note the runtime (`APP_RUNTIME`: docker or local) and proxy mode (`APP_PROXY_MODE`: forward or reverse).
- If it does not exist, the user is running standalone (no scaffold app).

## Step 2: Ask the user these questions (ask all at once, in a single message)

1. **Symptom**: What are you seeing? Choose the closest match:
   - 499 errors on some or all requests
   - HTTPS/certificate errors (SSL handshake failures, untrusted cert warnings)
   - Traffic not being intercepted (requests going directly to the real service)
   - Wrong or stale responses (getting old recorded data or unexpected responses)
   - Port conflict (Stoobly won't start, address already in use)
   - Something else — describe it

2. **Setup**: Are you using a scaffold app or running Stoobly standalone?

3. **Context**: Did this show up while running an E2E test (Playwright, Cypress, etc.), or during general usage?

**Routing check — do this before Step 3.** If the answer to question 3 is that the problem surfaced during an E2E test run, hand off now regardless of which symptom was chosen in question 1. `stoobly-troubleshoot-e2e-test` covers test-framework log cross-referencing, trace inspection, and the recording-fix workflow that this skill does not.

To hand off:

1. Invoke the `stoobly-troubleshoot-e2e-test` skill using your assistant's skill invocation (in Claude Code, the Skill tool or `/stoobly-troubleshoot-e2e-test`).
2. If that skill is not installed, read it directly and follow its steps in order:
   - Local: `.stoobly/docs/getting-started/configuring-an-ai-assistant/Skills/stoobly-troubleshoot-e2e-test.md`
   - URL fallback: https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/Skills/stoobly-troubleshoot-e2e-test
3. Carry over what Step 1 already established so the other skill does not rediscover it — whether `.stoobly/services/.config.yml` exists, and the `APP_RUNTIME` / `APP_PROXY_MODE` values.

Do not continue to Step 3 below — `stoobly-troubleshoot-e2e-test` owns the rest of the diagnosis. Return here only if it concludes the cause is environmental (certificate, port conflict, or intercept never enabled).

## Step 3: Read the relevant docs

Based on the symptom, read the corresponding local doc. If the local file doesn't exist, fetch the URL fallback instead.

| Symptom | Local doc | URL fallback |
|---|---|---|
| 499 errors | `.stoobly/docs/guides/how-to-mock-apis/troubleshooting.md` | https://docs.stoobly.com/guides/how-to-mock-apis/troubleshooting |
| HTTPS / cert errors | `.stoobly/docs/faq/ca-cert.md` | https://docs.stoobly.com/faq/ca-cert |
| Traffic not intercepted | `.stoobly/docs/faq/intercept.md` and `.stoobly/docs/faq/run.md` | https://docs.stoobly.com/faq/intercept and https://docs.stoobly.com/faq/run |
| Wrong / stale responses | `.stoobly/docs/guides/how-to-mock-apis/troubleshooting.md` | https://docs.stoobly.com/guides/how-to-mock-apis/troubleshooting |
| Port conflict | `.stoobly/docs/faq/run.md` | https://docs.stoobly.com/faq/run |

If the user has a scaffold app, also read the runtime-specific doc:
- Docker: `.stoobly/docs/faq/scaffold/runtime/docker.md`
- Local: `.stoobly/docs/faq/scaffold/runtime/local.md`

## Step 4: Run diagnostics and fixes

Using the docs you just read, determine the exact diagnostic and fix commands for their specific setup (scaffold+docker, scaffold+local, or standalone).

**Always start by checking the logs** — run these immediately before anything else:

For scaffold apps:
```bash
# Show what requests the workflow saw and their mock/record status
stoobly-agent scaffold request logs list <workflow>   # e.g. mock, record, test

# Show the raw workflow process output (startup errors, config issues)
stoobly-agent scaffold workflow logs <workflow>
```

For standalone (no scaffold):
```bash
# Show intercepted request logs (supports --follow, --level, --status-code filters)
stoobly-agent request logs list
```

Run diagnostic commands immediately using Bash (no confirmation needed — these are read-only checks). Show the output and interpret it for the user.

For fix commands, show what you plan to run and ask: "Ready to apply this fix? (yes / let me review first)" Once confirmed, execute each fix command using Bash. After each command, report whether it succeeded or failed. If a command fails, stop and show the full error output before asking how to proceed.

## Step 5: Surface next steps

End with context-appropriate next steps. Examples:

> - If you resolved a 499 issue: run the scaffold mock workflow again to confirm responses are now served correctly.
> - If you updated recordings: run scaffold test workflow to verify the new recordings match the live API.
> - If you're still stuck: check logs with `stoobly-agent scaffold request logs list <workflow>` and `stoobly-agent scaffold workflow logs <workflow>` (scaffold), or `stoobly-agent request logs list` (standalone), and look for error messages.
> - If the problem is happening inside a failing scaffold E2E test (Playwright/Cypress) and isn't resolved, switch to `stoobly-troubleshoot-e2e-test` (or read `.stoobly/docs/getting-started/configuring-an-ai-assistant/Skills/stoobly-troubleshoot-e2e-test.md` / https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/Skills/stoobly-troubleshoot-e2e-test if not installed) for the deep test-log cross-referencing and recording-fix workflow.
>
> Docs: https://docs.stoobly.com/faq/troubleshooting
````


# Troubleshoot E2E Test

````markdown
---
name: stoobly-troubleshoot-e2e-test
description: Troubleshoots E2E test failures by correlating Stoobly workflow request logs with Playwright or Cypress output. Use when E2E tests fail in CI or locally, mocks behave incorrectly, requests are not intercepted, or the user asks to debug scaffold test or mock workflows.
---

# Troubleshoot E2E Test

You are helping the user debug a failing E2E test.

## Instructions

Follow these steps in order when a scaffolded E2E test fails.

### 1. Resolve paths and running workflow

**Resolve app and context directories.** 

Run:

```bash
stoobly-agent scaffold describe
```

The command prints JSON with `app_dir_path`, `context_dir_path`, and config. 

Use the paths as follows for the rest of this skill:

- **Scaffold commands** (`stoobly-agent scaffold ...`) — run from `app_dir_path` (or pass `--app-dir-path <app_dir_path>`).
- **All other commands** (`stoobly-agent scenario ...`, `stoobly-agent request ...`, `stoobly-agent describe`, etc.) — run from `context_dir_path`.

```bash
cd <app_dir_path>
```

**Determine the running workflow.** From the app directory, run:

```bash
stoobly-agent scaffold workflow show
```

Note the `Workflow` name from the output (for example `test` or `mock`). Use that name as `<workflow>` in the steps below. If no workflow is running, ask the user which workflow they used for the failing test.

### 2. Get workflow request logs

From the app directory, list Stoobly workflow request logs. These show which requests were intercepted and whether each was mocked, passed through, or failed.

```bash
stoobly-agent scaffold request logs list <workflow>
```

Useful flags:

```bash
stoobly-agent scaffold request logs list <workflow> --level error
stoobly-agent scaffold request logs list <workflow> --message "Mock failure"
```

### 3. Cross-reference request logs with test framework logs

**Determine the E2E test framework.** Identify whether the project uses Playwright, Cypress, or another runner. Check scaffold plugins, `package.json` devDependencies, or config files (`playwright.config.ts`, `cypress.config.ts`).

**Find the framework logs.** Collect the test runner output for the failing test. For Playwright, inspect the **trace** when available — it is the recommended starting point for network activity and step-by-step execution.

**CI (failed run artifacts).** Use the trace, screenshot, and video from the failed CI run. Do not re-run the test with different flags to debug — re-running can change timing, data, or pass flakily.

```bash
npx playwright show-trace <trace.zip>   # from CI artifacts or test-results/
```

**Local (reproduce and capture).** Re-run with tracing only when debugging locally and no trace from the failure exists yet:

```bash
npx playwright test --trace on
npx playwright show-trace <trace.zip>
```

For Cypress, use the Cypress runner output, screenshots, and the Network tab in browser DevTools. In CI, use uploaded screenshots and videos from the failed run rather than re-running with different settings.

**Cross-reference framework logs with Stoobly workflow request logs.** For each failing request:

1. Find the URL, method, and approximate timestamp in the test framework logs (or Playwright trace network panel).
2. Find the same request in `stoobly-agent scaffold request logs list <workflow>`.
3. Compare status codes and response bodies.

If viewing the response body is needed, note the `request_key` and `context_dir_path` from the logs. Change directory to `context_dir_path` and run the following command:

```bash
stoobly-agent request response show <REQUEST-KEY>
```

Do not read snapshot files under `.stoobly/snapshots/` directly — always inspect mocks through `stoobly-agent request response show`.

### 4. Determine the root cause

**Read the test and the code under test (CUT) first.** Before diagnosing Stoobly configuration, open the failing test file and the application or service code it exercises. Understanding what the test expects and what the CUT actually requests clarifies whether a missing mock is a Stoobly misconfiguration or an intentional gap.

#### Status 499 or wrong recorded response in Stoobly request logs

A **499** status code means Stoobly intercepted the request but could not find a matching recorded request in the scenario. Confirm the failing request appears in workflow request logs with status 499 before proceeding.

A 499 can mean one of the following:

1. **No scenario key or name was passed.** The interceptor ran without `withScenarioKey()` / `withScenarioName()` (or equivalent), so Stoobly had no scenario to search. Warn the user and point them to set a scenario before enabling intercept. See [JS client troubleshooting](../../../faq/scaffold/e2e-testing/js-client/troubleshooting.md).

2. **The request was never recorded** — often because a filter rule in `.stoobly/settings.yml` excluded it, because the **record policy** is `api`, or because of the record strategy in use. That may be intentional. Use the test and CUT from above to decide whether the CUT actually needs that request:
   - If the CUT does **not** need it, treat the 499 as expected noise, or update the test (for example assertions or steps that still expect that request).
   - If the CUT **does** need it, diagnose why recording was skipped:
     - Run `stoobly-agent intercept show` (from `context_dir_path`) to check the record policy. When policy is `api`, Stoobly records only responses whose `Content-Type` is JSON (`application/json` or `application/*json`), XML (`application/xml` or `application/*xml`), or `text/plain`. HTML pages, images, scripts, and other asset responses are not recorded — compare the failing request's response `Content-Type` in the test framework logs or Playwright trace.
     - Check `.stoobly/settings.yml` for filter rules that exclude the request.
     - If `api` policy skipped a response the CUT needs, change to `all` and re-record: `stoobly-agent intercept set --mode record --policy all`, then run the record workflow again. If a filter rule blocked it, adjust that rule instead.
     - If a response should qualify under `api` but was still skipped (for example missing or incorrect `Content-Type`), fix the upstream response or use `all` policy when re-recording.

#### Request in test framework logs but not in Stoobly request logs

If the failing request appears in the test framework logs but not in Stoobly workflow request logs, it is not a 499 issue — the request was never intercepted. Check whether the test framework (for example Cypress or Playwright) has its proxy setting configured so traffic is routed through Stoobly.

#### Cause is environmental rather than test-specific

If the evidence points at setup rather than the test — HTTPS/certificate failures, a port conflict, Stoobly failing to start, or intercept never enabled — hand back to `stoobly-triage`, which owns those fixes. Invoke it via your assistant's skill invocation, or read `.stoobly/docs/getting-started/configuring-an-ai-assistant/Skills/stoobly-triage.md` (URL fallback: https://docs.stoobly.com/getting-started/configuring-an-ai-assistant/Skills/stoobly-triage). Pass along the workflow name and anything already learned from `stoobly-agent scaffold describe`.

#### No mock issues found in Stoobly request logs

If workflow request logs and test framework logs show no mock mismatches, missing interception, or other Stoobly issues, the likely cause is that the **test itself needs to be updated** — for example assertions, selectors, or expected UI/API behavior that no longer match the application. Update the test accordingly rather than changing Stoobly configuration or mocks.

#### Git status reveals uncommitted snapshots

If `git status` shows uncommitted files under `.stoobly/snapshots/`, the mocks were likely updated recently and are still correct. **Do not modify them.**

To inspect a mock, use the request response show command (never edit snapshot files by hand):

```bash
stoobly-agent request response show <REQUEST-KEY>
```

Uncommitted snapshots also point away from a Stoobly mock problem and toward a **test-related issue** — for example assertions, selectors, or expected UI/API behavior that no longer match the application. Focus on updating the test rather than changing mocks or Stoobly configuration.

## Reference documentation

| Topic | Doc |
| ----- | --- |
| Scaffold workflow logs | [Scaffold FAQ](../../../faq/scaffold/README.md) |
| Playwright integration | [Playwright](../../../faq/scaffold/e2e-testing/js-client/playwright.md) |
| Cypress integration | [Cypress](../../../faq/scaffold/e2e-testing/js-client/cypress.md) |
| Mock troubleshooting | [Troubleshooting](../../../guides/how-to-mock-apis/troubleshooting.md) |
| Configuration | [Config](../../../faq/config.md) |
| Request commands | [Request](../../../faq/request.md) |
| Scenario commands | [Scenario](../../../faq/scenario.md) |
| Snapshots | [Snapshot](../../../faq/snapshot.md) |
| Update request or response | [Update Request](stoobly-update-request.md) |
| Triage general Stoobly problems | [Triage](stoobly-triage.md) |
| E2E JS client troubleshooting | [JS client troubleshooting](../../../faq/scaffold/e2e-testing/js-client/troubleshooting.md) |
````


# Update Request

````markdown
---
name: stoobly-update-request
description: Updates a recorded request and/or its response via the Stoobly CLI, then persists the change with a request snapshot. Use when a mock response is wrong or outdated, a recorded request body/URL/method/headers need changing, or the user asks to update a request or response without editing snapshot files by hand.
---

# Update Request

You are helping the user update a recorded request and/or its response.

## Instructions

Follow these steps when a stored request or response needs to change. Do not edit snapshot files directly. Scaffold E2E tests version snapshots under `.stoobly/snapshots/`.

### 1. Resolve the context directory

Run all `request` and `scenario` commands from the context directory (the directory that contains `.stoobly`).

If you do not already know the path, run:

```bash
stoobly-agent scaffold describe
```

Use `context_dir_path` from the JSON output:

```bash
cd <context_dir_path>
```

### 2. Identify the request key

You need `<REQUEST-KEY>` before updating. If the caller already provided it, skip to Step 3.

**From a scenario:**

```bash
stoobly-agent scenario list --search "<scenario or test name>"
stoobly-agent request list --scenario-key <SCENARIO-KEY>
```

**From a URL or path search:**

```bash
stoobly-agent request list --search "/api/users"
```

Note the `key` for the request to update.

### 3. Inspect the current request and response

```bash
stoobly-agent request response show <REQUEST-KEY>
```

Compare the stored request/response with the expected values (body, status, headers, method, path, and so on).

### 4. Update the local database

Apply only the fields that need to change.

**Response** — body, status, headers, or latency:

```bash
stoobly-agent request response update <REQUEST-KEY> --body '{"id":1}'
stoobly-agent request response update <REQUEST-KEY> --status 201
stoobly-agent request response update <REQUEST-KEY> --header Content-Type:application/json
stoobly-agent request response update <REQUEST-KEY> --header X-Deprecated:
stoobly-agent request response update <REQUEST-KEY> --latency 500
```

**Request** — body, URL parts, method, or headers:

```bash
stoobly-agent request update <REQUEST-KEY> --body '{"name":"Alice"}'
stoobly-agent request update <REQUEST-KEY> --method POST --path /api/users
stoobly-agent request update <REQUEST-KEY> --header Authorization:Bearer token
```

Use `--header NAME:` with an empty value to delete a header.

### 5. Verify the update

```bash
stoobly-agent request response show <REQUEST-KEY>
```

Confirm the stored data matches expectations. If this change is for a failing E2E test, re-run that test to confirm the mock behaves correctly before persisting anything to version control.

### 6. Persist to version-controlled snapshots

```bash
stoobly-agent request snapshot create <REQUEST-KEY> --decode
```

Commit the updated snapshot file(s) under `.stoobly/snapshots/` so the change is available locally and in CI.

## Reference documentation

| Topic | Doc |
| ----- | --- |
| Request commands | [Request](../../../faq/request.md) |
| Snapshots | [Snapshot](../../../faq/snapshot.md) |
| Updating requests | [How to Update Requests](../../../guides/how-to-update-requests/README.md) |
| Troubleshoot E2E test | [Troubleshoot E2E Test](stoobly-troubleshoot-e2e-test.md) |
````


# Agent

Overview of Stoobly agent (stoobly-agent)

Stoobly agent is a [man-in-the-middle proxy](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) that can intercept HTTP(s) requests to use for recording, mocking and replaying.

It is made of three main components:

* A proxy server
* A dashboard web interface
* A command-line interface

## Proxy Server

The proxy server is an extension of the open-source [mitmproxy](https://github.com/mitmproxy/mitmproxy) project.

## Web Interface

The web UI can be used to create, view, update and delete requests and scenarios. It also has convenient buttons and drop-downs to change the agent mode to configure when you want to mock or record requests. Finally, it also provides an easy way to modify the proxy configuration for customizing rewrite and match rules.

## Command-Line Interface

The CLI is ideal for using Stoobly as part of scripts and CI pipelines. To see what the CLI offers:

```bash
$ stoobly-agent                                                                                                                                                                                                                          10s
```

```bash
Usage: stoobly-agent [OPTIONS] COMMAND [ARGS]...

Options:
  --version   Show the version and exit.
  -h, --help  Show this message and exit.

Commands:
  dev-tools  Access developer tools
  exec       Run shell command with proxy enabled
  feature    Manage features
  init       Initialize a new context
  mock       Mock request
  record     Record request

Proxy Commands:
  ca-cert    Manage CA certificate
  config     Manage proxy config
  intercept  Manage request intercept
  run        Run proxy and/or UI

Local Resource Commands:
  request    Manage requests
  scenario   Manage request scenarios

  Run 'stoobly-agent COMMAND --help' for more information on a command.
```


# Intercept Modes

{% hint style="info" %}
**Configures:** what should Stoobly do with intercepted requests?
{% endhint %}

## Accessing From UI

From the UI, the active intercept mode can be found in the header dropdown button next to **Proxy Mode**. In the following example, the active intercept mode is **Record:**

<div align="left"><figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-9a306846a87d90b5448258cf00d9b252bf54a35e%2Frecord-button.png?alt=media" alt="" width="339"><figcaption><p>Stoobly UI header showing Record intercept mode</p></figcaption></figure></div>

## Accessing From CLI

From the CLI, the active intercept mode can be show by running the following command:

```bash
stoobly-agent intercept show
```

## Available Intercept Modes

{% content-ref url="/pages/F4GwOw5lITXWirA20AaR" %}
[Mocking](/core-concepts/agent/intercept-modes/mocking)
{% endcontent-ref %}

{% content-ref url="/pages/1TQ2FJxXcNdzBzODBBom" %}
[Recording](/core-concepts/agent/intercept-modes/recording)
{% endcontent-ref %}


# Mocking

The goal of mocking HTTP requests is to simulate the behavior of an actual API. This can involve:

* Returning hard-coded responses
* Returning recorded reponses
* Generating responses

Stoobly's mocking relies on returning hard-coded or recorded responses.

## How are requests matched?

### Scenario

{% hint style="info" %}
If a scenario is specified, then only requests within that scenario will be considered.
{% endhint %}

{% hint style="warning" %}
If no scenario is specified, then any request will be considered.
{% endhint %}

If there are multiple matches in a scenario, then each response will be returned in the order in which they were recorded.

### Components

The following request components are matched in a case-sensitive manner:

* HTTP Method
* Path
* Body
* Query Parameters
* Headers
* Body Parameters

#### HTTP Method

Which HTTP method(s)/verb(s) the rule applies to such as GET, POST, DELETE, etc.

#### Path

e.g. `/users`

#### Body

If provided, a strict matching of the body is required.

{% hint style="info" %}
The following requests components can be marked as optional in the UI. An optional request component will not be used for matching purposes when mocking a request. To learn more, visit [here](/core-concepts/agent/proxy-settings/match-rules).
{% endhint %}

#### Query Parameters

e.g. `?organization=1`

The order of the query parameters are sorted in alphabetical order before comparison.

#### Headers

e.g. `Content-Type: application/json`

The order of the headers are sorted in alphabetical order before comparison.

#### Body Parameters

Body parameters are dependent on the `Content-Type` header in the request. If the body is a parseable format, body parameters will be parsed out, sorted in alphabetical order, and compared. The following parseable formats are currently supported:

* `application/json`
* `application/x-www-form-urlencoded`

## When are requests matched?

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-40a2b9bce88ec7dd21f164ec396edf502a1f681a%2Fmock.simple.png?alt=media" alt=""><figcaption><p>Mocking a HTTP request with Stoobly</p></figcaption></figure>


# Recording

In the context of Stoobly, recording means to intercept HTTP requests with the agent and save them to the local filesystem.

## Why record HTTP requests?

Recording HTTP requests saves previously seen requests and their responses. This enables you to:

* Mock future requests that match and return realistic data
* Replay requests at any time
* Gain deeper insight into a scenario's requests

## What gets recorded?

The following HTTP request components get recorded:

* Hostname
* Port number
* Path
* Headers
* Query Parameters
* Body
* Response Headers
* Response Body

## When are HTTP requests recorded?

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-b62c174e6c0194461aba8d136706fa0b54f8c94d%2Frecord.simple.png?alt=media" alt=""><figcaption><p>Recording a HTTP request with Stoobly</p></figcaption></figure>


# Lifecycle Hooks

{% hint style="info" %}
We currently only support lifecycle hook scripts written in Python.
{% endhint %}

## What are Lifecycle Hooks?

A lifecycle hook is a way to add custom functionality during specific events in the life of a Stoobly resource such as a request or a response.

Stoobly's Lifecycle Hooks can be written as Python functions which use the Stoobly Python library to hook into these events and do addtional tasks.

## Why use Lifecycle Hooks?

These hooks enable you to add custom functionality with your own code at different stages.

Some examples include:

* Rewriting a header's value before or after its request gets sent to not store sensitive data
* Adding, removing or modifying data such as in headers, query parameters, bodies, etc.
* Adding extra debug information or publishing metrics

## What are the Different Lifecycle Hook Events Supported?

<details>

<summary>handle_before_request</summary>

```python
from stoobly_agent.app.proxy.context import InterceptContext

def handle_before_request(context: InterceptContext):
    pass
```

</details>

<details>

<summary>handle_before_record</summary>

```python
from stoobly_agent.app.proxy.record.context import RecordContext

def handle_before_record(context: RecordContext):
    pass
```

</details>

<details>

<summary>handle_before_mock</summary>

```python
from stoobly_agent.app.proxy.mock.context import MockContext

def handle_before_mock(context: MockContext):
    pass
```

</details>

<details>

<summary>handle_before_test</summary>

```python
from stoobly_agent.app.proxy.test.context import TestContext

def handle_before_mock(context: TestContext):
    pass
```

</details>

<details>

<summary>handle_after_record</summary>

```python
from stoobly_agent.app.proxy.record.context import RecordContext

def handle_after_record(context: RecordContext):
    pass
```

</details>

<details>

<summary>handle_after_mock</summary>

```python
from stoobly_agent.app.proxy.mock.context import MockContext

def handle_after_mock(context: MockContext):
    pass
```

</details>

<details>

<summary>handle_after_test</summary>

```python
from stoobly_agent.app.proxy.test.context import TestContext

def handle_after_test(context: TestContext):
    pass
```

</details>

<details>

<summary>handle_before_replay</summary>

```python
from stoobly_agent.app.proxy.replay.context import ReplayContext

def handle_before_replay(context: ReplayContext):
    pass
```

</details>

<details>

<summary>handle_after_replay</summary>

```python
from stoobly_agent.app.proxy.replay.context import ReplayContext

def handle_after_replay(context: ReplayContext):
    pass
```

</details>

<details>

<summary>handle_before_response</summary>

```python
from stoobly_agent.app.proxy.context import InterceptContext

def handle_before_response(context: InterceptContext):
    pass
```

</details>

<details>

<summary>handle_before_request_component_create</summary>

```python
from stoobly_agent.app.proxy.test.context import TestContext

def handle_before_request_component_create(context: TestContext):
    pass
```

</details>

<details>

<summary>handle_before_request_component_delete</summary>

```python
from stoobly_agent.app.proxy.test.context import TestContext

def handle_before_request_component_delete(context: TestContext):
    pass
```

</details>

For the full list, see [this link](https://github.com/Stoobly/stoobly-agent/blob/master/stoobly_agent/config/constants/lifecycle_hooks.py) to the Stoobly Python definitions of the events available. All of the strings on the right side of the variable assignment are also the function names available in lifecycle hook scripts.

## Types of Contexts

There are several types of contexts available for your scripts. The parameter type will change depending on what type of hook you are using. To see the fields and methods available, view the full definition as well as any parent classes they might be inherited from.

#### RecordContext

For record events use the `RecordContext`. The full definition can [be found here](https://github.com/Stoobly/stoobly-agent/blob/master/stoobly_agent/app/proxy/record/context.py).

To import it, add this to the top of your script:

```python
from stoobly_agent.app.proxy.record.context import RecordContext
```

#### ReplayContext

For replay events use the `ReplayContext`. The full definition can [be found here](https://github.com/Stoobly/stoobly-agent/blob/master/stoobly_agent/app/proxy/replay/context.py).

To import it, add this to the top of your script:

```python
from stoobly_agent.app.proxy.replay.context import ReplayContext
```

#### MockContext

For mock events use the `MockContext`. The full definition can [be found here](https://github.com/Stoobly/stoobly-agent/blob/master/stoobly_agent/app/proxy/mock/context.py).

To import it, add this to the top of your script:

```python
from stoobly_agent.app.proxy.mock.context import MockContext
```

## Enabling Lifecycle Hook Scripts Use

Once your script is written, it can now be used by the Agent. Lifecycle hooks are supported for the following commands:

* `stoobly-agent run`
* `stoobly-agent request replay`
* `stoobly-agent scenario replay`
* `stoobly-agent endpoint import`

## Next Steps

Next see our guide on how to create your own lifecycle hooks and how to use them:

{% content-ref url="/pages/L80ROjPjA3paJPSgdFzA" %}
[How to Customize Recordings](/guides/how-to-record-requests/how-to-customize-recordings)
{% endcontent-ref %}


# Proxy Settings

Enables additional configuration on how to handle requests

To access the proxy settings from the UI, click on the cog button in the following screenshot:

<div align="left"><figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-9a306846a87d90b5448258cf00d9b252bf54a35e%2Frecord-button.png?alt=media" alt="" width="339"><figcaption></figcaption></figure></div>

Alternatively, it can also be found by visiting [http://localhost:4200/a](http://localhost:4200/proxy/settings)[gent/proxy-settings](http://localhost:4200/agent/proxy-settings).

{% hint style="info" %}
This assumes that the UI was configured to run on port 4200 (default)
{% endhint %}

## Sections

There are four sections in the proxy settings:

{% content-ref url="/pages/RX6Ks2VkMoeWw5v6Z0TE" %}
[Data Rules](/core-concepts/agent/proxy-settings/data-rules)
{% endcontent-ref %}

{% content-ref url="/pages/qs8imD4qtRLHTxh0jvvY" %}
[Filter Rules](/core-concepts/agent/proxy-settings/filter-rules)
{% endcontent-ref %}

{% content-ref url="/pages/ApdxVmlQwhHVqhd8SEgk" %}
[Rewrite Rules](/core-concepts/agent/proxy-settings/rewrite-rules)
{% endcontent-ref %}

{% content-ref url="/pages/x3jsEOejcOfRNTlITO8F" %}
[Match Rules](/core-concepts/agent/proxy-settings/match-rules)
{% endcontent-ref %}


# Data Rules

{% hint style="info" %}
**Configures:**

* Which scenario to use?
* Which policy to use for a particular [Stoobly mode](/core-concepts/agent/intercept-modes)?
  {% endhint %}

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-44f6673ab96ea05b96ba3e4df61038bcec61ce65%2Fproxy-settings-sept-2023.png?alt=media" alt=""><figcaption></figcaption></figure>

## Source or Destination

{% hint style="info" %}
Answers: Where to record/mock requests?
{% endhint %}

For recording, this setting controls which scenario the request will be saved to. For all other modes, this setting controls which scenario the request will be searched from.

## Policy

{% hint style="info" %}
Answers: Which requests to record/mock?
{% endhint %}

### Record Policy

Record policy settings controls what to do with requests received by the agent. By default, the agent will record `all` requests intercepted.

To configure the record policy, go to the Proxy Settings by clicking on the cog next to the Run button. Below is similar to what you will see.

<div align="left"><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-5efb171faa18130b127cf382d306fbf347c71f19%2FScreen%20Shot%202023-04-12%20at%209.57.08%20AM.png?alt=media" alt="Figure 1. Record policy settings"></div>

The following describes the behaviour of each record policy:

<table><thead><tr><th width="201.71124589450892">Policy</th><th>Description</th></tr></thead><tbody><tr><td>all</td><td>All requests will be recorded</td></tr><tr><td>not_found</td><td>Only requests not previously recorded will be recorded</td></tr><tr><td>overwrite</td><td>Active scenario will be overwritten with record requests</td></tr></tbody></table>

### Mock Policy

Mock policy settings controls what to do with requests received by the agent.

By default, the agent will only mock `found` requests.

<div align="left"><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-755161f13d41864dc717f7daed20d771dce46251%2FScreen%20Shot%202023-04-12%20at%209.57.08%20AM.png?alt=media" alt="Figure 2. Mock policy settings"></div>

The following describes the behaviour of each mock policy:

<table><thead><tr><th width="210.6632398448366">Policy</th><th>Description</th></tr></thead><tbody><tr><td>all</td><td>All requests will be mocked</td></tr><tr><td>found</td><td>Only requests that have been recorded will be mocked</td></tr></tbody></table>


# Filter Rules

{% hint style="info" %}
**Configures:**

* Which requests to record/mock?
  {% endhint %}

{% hint style="info" %}
Filter rules are applied after [data rules](/core-concepts/agent/proxy-settings/data-rules).
{% endhint %}

This section provides fine-grained configuration to control which requests are recorded, mocked or replayed. Rules are applied if a request URL matches the provided regex **pattern.**

## Rule Configuration

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-7162afacf01f1d927959149f88bfe1874273386f%2FScreen%20Shot%202023-04-12%20at%209.55.51%20AM.png?alt=media" alt=""><figcaption><p>Figure 1. Filter rule</p></figcaption></figure>

## Rule Components

### Method

HTTP verb(s) the rule applies to such as GET, POST, DELETE, etc.

### Pattern

Pattern to match with the request URL to apply the rule to. This supports regular expressions.

### Action

Whether to include or exclude requests that match.

### Modes Applied To

Which agent mode to apply the filter rule to such as mock, record and/or replay

## Example

For example, maybe you want to exclude recording requests that generate OAuth tokens. And let's assume that the endpoint is `POST https://internal.company.com/v1/token` . You can then create a rule with the following values:

* Method - `POST`
* Pattern - `https://internal.company.com/v1/token`
* Action - `Exclude`
* Modes Applied To - `Record`

##


# Rewrite Rules

How to rewrite portions of requests

{% hint style="info" %}
**Configures:**

* How to modify parts of a request?
  {% endhint %}

Rewrite rules enable modification of any part of a request. Rules are applied if a request URL matches the provided regex **pattern.** If there are no rewrite rules or a request URL does not match any of the rule patterns, then there will be no modifications to the intercepted request.

## Rule Configuration

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-480a9ef791021be7d54d63c1ece60ba34bf717e6%2FScreen%20Shot%202023-04-12%20at%2010.44.04%20AM.png?alt=media" alt=""><figcaption><p>Figure 1. Rewrite rule</p></figcaption></figure>

### Method

HTTP verb(s) the rule applies to such as GET, POST, DELETE, etc.

### Pattern

Pattern to match with the request URL to apply the rule to. This supports regular expressions.

### Parameters

Which components of the request to match on, such as header, body, and query param.

### Name

Name of the component

e.g. for the header `Authorization: Token` , the name is `Authorization`

### Value

Value of the component

e.g. for the header `Authorization: Token` , the value is `Token`

### Modes Applied To

Which agent mode to apply the filter rule to such as mock, record and/or replay

## Example

For example, say you want to record requests to endpoints that require valid OAuth tokens. Let's say that endpoint is `GET https://internal.company.com/v1/users` . Then you can create a rewrite rule with the following values:

* Method - `GET`
* Pattern - `https://internal.company.com/v1/users`
* Parameter Type - `Header`
* Parameter Name - `Authorization`
* Value - `REDACTED TOKEN`
* Modes Applied To - `Record`

When recording, this will configure the agent to rewrite the `Authorization` header's value with `REDACTED TOKEN`. Similarly, when replaying a request, we can also create a rule set this same header with a valid token. For advance use cases, see:

{% content-ref url="/pages/L80ROjPjA3paJPSgdFzA" %}
[How to Customize Recordings](/guides/how-to-record-requests/how-to-customize-recordings)
{% endcontent-ref %}


# Match Rules

How to define extra rules to match requests

{% hint style="info" %}
**Configures:**

* How to relax constraints when matching requests?
  {% endhint %}

{% hint style="info" %}
Match rules only apply to mocking mode.
{% endhint %}

Matching rules allow you customize which component categories of a request are used for matching. By defualt, only request **query params** and **body** are used for matching. Request **method** and **path** are required for matching and not configurable.

## Rule Configuration

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-d323db51875d6183577c1526eeba2552f32b0b73%2FScreen%20Shot%202023-04-12%20at%2010.44.47%20AM.png?alt=media" alt=""><figcaption><p>Figure 1. Matching rules</p></figcaption></figure>

### Method

HTTP verb(s) the rule applies to such as GET, POST, DELETE, etc.

### Pattern

Pattern to match with the request URL to apply the rule to. This supports regular expressions.

### Component

Which components of the request to match on, such as header, body, and query param.

### Modes Applied To

Which agent mode to apply the filter rule to such as mock.


# Context

## What is a Stoobly Context?

A context is collection of [requests](/core-concepts/mock-api/requests) and [scenarios](/core-concepts/mock-api/scenarios).

### Default Context

The default context is automatically generated and set when you run `stoobly-agent` for the first time. Contexts are maintained by the hidden directories named `.stoobly` . For supported OSs the default context's data will be in the user's home directory e.g. `~` or `$HOME` for unix systems.

## Why have different Contexts?

### Separation of APIs

A context contains [scenarios](/core-concepts/mock-api/scenarios) which are used to group requests for a user workflow. As more scenarios are created, they may become more and more loosely related. To differentiate the scenarios of various APIs, it is recommended to consider separating them with a new context. Recommended separation strategies:

* One context per API service
* One context per application

### Collaboration

Sharing contexts can be useful to show collaborators all the data for an API instead of manually exporting specific requests and scenarios and having them import each one. Instead you can share the entire context and quickly onboard teammates.


# Mock API


# Request

A Stoobly request represents a HTTP request

{% hint style="info" %}
Enables mocking, testing, and replaying
{% endhint %}

## Fields

<details>

<summary>Hostname</summary>

Name of the host where the request was received at

</details>

<details>

<summary>Port</summary>

Port where the request received at

</details>

<details>

<summary>Path</summary>

Request path e.g. /users/1

</details>

<details>

<summary>Latency</summary>

Response latency in milliseconds

</details>

<details>

<summary>Status</summary>

Response status code

</details>

## Components

<details>

<summary>Headers</summary>

List of **name** and **value** pairs respectively representing the header name and header value

</details>

<details>

<summary>Query Params</summary>

List of **name** and **value** pairs respectively representing the query param name and query param value

</details>

<details>

<summary>Body</summary>

Data of blob format representing the request body

</details>

<details>

<summary>Response</summary>

Represents a HTTP response. See details [here](/core-concepts/mock-api/requests/response)

</details>

<details>

<summary>Response Headers</summary>

List of **name** and **value** pairs respectively representing the response header name and response header value

</details>

## Request Key

Every request will have a unique identifier for your Stoobly context. This can be retrieved from the UI or the CLI.

### From the UI

Navigate to the requests page then click on a request. This will open the request details page from the right side. At the top there will be a **Key** field which is the request Key.

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-12616ef7a9aa20e47d3e3ce04087cf475011ba62%2FScreenshot%202023-05-03%20141009%20-%20request%20key.png?alt=media" alt=""><figcaption><p>Request Key in the details page</p></figcaption></figure>

### From the CLI

Run the following command to view some requests:

```
$ stoobly-agent request list

method    host                path     port  body_text_hash    query_params_hash      body_params_hash  committed_at  latency  query  status    is_deleted    http_version  key
GET       localhost           /users   8081                    cddd9a61a91320bb71702                                      287            200             0             1.1  eyJwIjogMCwgImkiOiA0MjR9
```

Here in our example we have a single request. The request key can be found in the `key` column. In the example above, it is`eyJwIjogMCwgImkiOiA0MjR9`.


# Response

A Stoobly response represents a HTTP request's response

A Stoobly response is tightly coupled to a Stoobly request. It contains additional data such as the HTTP response code and round-trip latency.

## Components

<details>

<summary>Headers</summary>

List of **name** and **value** pairs respectively representing the response header name and response header value

</details>

<details>

<summary>Body</summary>

Data of blob format representing the request body

</details>

## How To Create Responses

If you are recording a HTTP request, a Stoobly request and associated response will be created.


# Replay History

## What is the Replay History?

The replay history is a list of previously recorded replays of a request.

## How to Access the Replay History?

To view a [Request](/core-concepts/mock-api/requests)'s replay history in the UI, click on that request. If you have not recorded anything yet, it will be empty.

But once you have replayed it (see [the recording requests guide](/guides/how-to-record-requests)), the list will show the replayed instances and will contain request data such as the headers, response body, timestamps as well as an option to **Activate** it to overwrite the original response with that one's.

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-b38487a7f9cdf891d33477b2ced0c2b8030e0648%2FScreenshot%202023-05-03%20105552.png?alt=media" alt=""><figcaption><p>Figure 1. Replay History</p></figcaption></figure>

In the screenshot, the request was replayed four times. The replay history enables us to see detailed information on those four replayed requests.


# Scenarios

A Stoobly cenario is a sequence of requests that describes a workflow

{% hint style="info" %}
**Use Cases:**

* Replaying or testing requests in a sequence
* Documenting common workflows
* Sharing those workflows with others
  {% endhint %}

## What is a Scenario?

Take for example in a new user registration flow for some hypothetical application, the following HTTP requests are sent:

1. `POST /user` to create the new user
2. `GET /user/{user_id}` to retrieve data about the user
3. `GET /products` to retrieve a store's list of products to present to the user

This sequence of requests is specific for that workflow, has a defined order and can tied together. This enables you to group requests together, share them with other engineers or even replay the whole sequence. This is what we define as a scenario.

## How To Create Scenarios

If using the UI, navigate to the Scenarios page and click on the **CREATE** button on the top left corner.

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-eeebc3a897fba0d888f9654b5c29192a46df65eb%2Fscenarios-index-create.PNG?alt=media" alt=""><figcaption><p>Scenarios Create</p></figcaption></figure>

For our full guide, see [How to Create Scenarios ](#how-to-create-scenarios).

## Scenario Key

Every Scenario will have a unique identifier for your Stoobly context. This can be retrieved from the UI or the CLI.

### From the UI

Navigate to the scenarios page then click on a scenario. This will open the scenario details page from the right side. At the top there will be a **Key** field which is the scenario key.

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-b1658076a5a4547b50e0778f2128a50efe9a8ca5%2FScreenshot%202023-05-03%20021848%20-%20scenario%20key.png?alt=media" alt=""><figcaption><p>Scenario Key in the details page</p></figcaption></figure>

### From the CLI

Run the following command to view your scenarios:

```
$ stoobly-agent scenario list

  id  name                  requests_count  description      is_deleted  key
   1  My First Scenario                  1                            0  eyJwIjogMCwgImkiOiAzfQo=
```

Here in our example we have a single scenario. The scenario Key can be found in the `key` column which is `eyJwIjogMCwgImkiOiAzfQo=`.


# Snapshots

A Stoobly snapshot is a collection of requests and scenarios

## What are Snapshots?

{% hint style="info" %}
Think Git commits
{% endhint %}

Stoobly snapshots are point-in-time copies of your mock requests. They are a collection of request and scenario events along with meta needed to create or delete them. Snapshots can be useful for restoring to a previous state or can be used to share mock requests with others.

## Why use Snapshots?

* Save and backup requests and scenarios
* Share requests and scenarios
  * Version control requests and scenarios with Git

## Folder Structure

```
/home/user/.stoobly/snapshots
└── history
  └── 170052330
├── log
└── requests
    └── 4a
        └── 4a449553-b074-4782-809f-e52d8358da78
└── scenarios
    └── ea320e50-3a46-41ac-a8fc-a021402c22d6
    └── requests
        └── ea320e50-3a46-41ac-a8fc-a021402c22d6
└── VERSION
   
```

<details>

<summary>history</summary>

The `history` folder contains event bucket files such as `170052330` . These event bucket files contain events that occurred during a timeframe. These events are used to rebuild the mock state when snapshots are applied.

</details>

<details>

<summary>log</summary>

The `log` file contains events that were last applied. It should not be added to version control.

</details>

<details>

<summary>requests</summary>

The `requests` folder contains request bucket folders such as `4a` . These request bucket folders contain files such as `4a449553-b074-4782-809f-e52d8358da78` that contain the latest snapshot of a request.

</details>

<details>

<summary>scenario</summary>

The `scenarios` folder contains files such as `ea320e50-3a46-41ac-a8fc-a021402c22d6` that contain the latest **name** and **description** of a scenario. The folder also contains a `requests` folder that contains files such as `ea320e50-3a46-41ac-a8fc-a021402c22d6` that contain a list of requests that belong to the scenario.

</details>

<details>

<summary>VERSION</summary>

The `VERSION` file contains the uuids of events that were last applied. It should not be added to version control.

</details>

## Next Steps

{% content-ref url="/pages/Tyk5SmKa5es0I3YjLQA0" %}
[How to Snapshot Requests](/guides/how-to-mock-apis/how-to-snapshot-requests)
{% endcontent-ref %}


# Fixtures

## What are fixtures?

{% hint style="info" %}
Think API intercept and modify behavior in testing libraries
{% endhint %}

Stoobly fixtures are predefined responses used during mocking. Fixtures are used in the case where a recorded response is not found for the current request.

## **Why use fixtures?**

* Quick way to mock a request in the case where a specific response is difficult to record
* Serve assets that otherwise should not be recorded

## Example Fixtures YAML File

The following is an example file for a `fixtures-response.yml` passed to the `--fixtures-response-path` option:

```yaml
DELETE:
    /users/d+?:
        headers: {}
        path: ./relative-path-to-response
        status_code: 200
GET:
    /users/d+?:
        headers: {}
        path: ./relative-path-to-response
        status_code: 200
POST:
    /users:
        headers: {}
        path: ./relative-path-to-response
        status_code: 200
PUT:
    /users/d+?:
        headers: {}
        path: ./relative-path-to-response
        status_code: 200  
```

## Next Steps

{% content-ref url="/pages/GMxOwIvZkyegtOEnzG1D" %}
[How to Use Fixtures](/guides/how-to-mock-apis/how-to-use-fixtures)
{% endcontent-ref %}


# Public Folder

## What is the public folder?

During mocking, files within the public folder will be served based on their relative file path. For example, given the following files:

* `index.html`
* `users/1.json`

GET requests for `/` and `/index.html` will map to the file `index.html` .

GET requests for `/users/1` and `/users/1.json` will map to `users/1.json`

Based on the file extension, the file will also be served with a related conten type. For example:

`/users/1` will set a response header of `Content-Type: application/json`

## Defaults

Unless otherwise specified:

* `status_code` defaults to 200
* Response header `Content-Type` will be inferred from the fixture file extension

## **Why use the public folder?**

* Quick way to mock a request in the case where a specific response is difficult to record
* Serve assets that otherwise should not be recorded


# Scaffold

## Background

Without scaffold, setting up Stoobly to record and mock requests involves three core challenges:

* Service orchestration
  * Configure Stoobly to intercept traffic for multiple services
  * Dynamically generate SSL certificates
  * Support customization through adding user-defined services
* Consistent ease-of-use across team members
  * Stoobly version management
  * Automated onboarding
  * Opinionated process for recording, mocking, and testing
* Separating configuration for different workflows e.g. development and CI
  * Defining a consistent file structure across workflows
  * Scoping container to specific workflows
  * Namespacing containers to enable the same workflow to run multiple times

To solve these challenges, scaffold provides a framework to define services and customize workflows.

## What is Scaffold?

Scaffold is implemented as a CLI command to offer an out-of-the-box solution to build a containerized solution to record, mock, and test your applications. These workflows can be easily integrated into CI pipelines and test environments without needing to spend extra development time orchestrating a test setup.

With scaffold, we take an opinionated approach:

* Use Docker Compose to declaratively define all the services and networking configuration
* Automatically run Stoobly maintained services for the user such as 1 Stoobly UI, a `stoobly-agent` proxy per service, and a "Gateway" that intelligently routes requests to the correct service
* Describe apps and services in a declarative config file, applied with CLI commands that also work standalone for one-off changes
* Allow configuration to be provided in specific files with a consistent experience

As a result, we can enforce best practices and make it easy to run dozens of services in complex setups. There are also opinionated ways of running services and configuring everything correctly for different use-cases such as recording requests, mocking requests, or for a CI pipeline with end-to-end tests.

## Declarative Configuration

Scaffold commands can also be described in a single config file, `.stoobly/scaffold.yml`, and applied with `stoobly-agent scaffold apply`. Each step in the config maps 1:1 to a scaffold CLI command (`app create`, `service create`, `workflow up`, etc.), so an entire app-and-services setup can be reviewed, version-controlled, and reproduced by teammates with one command instead of a sequence of individual invocations. This is the recommended way to set up a scaffold.

{% content-ref url="/pages/vNbSv8Y3FUGMz3PL3GyX" %}
[Apply](/faq/scaffold/apply)
{% endcontent-ref %}

## Terminology

### Application

An application represents a source-controlled code repository that depends on one or more services.

### Networks

The following networks are created when running a workflow. When defining custom container services, they may need to belong in either (but not both) of the following networks:

* Specify `app.ingress` when container services need to reference a service by hostname.
* Specify `app.egress` when container services need to access or be accessed by other service containers.

### Service

A service represents an application dependency. The service is often, but not necessary responds to HTTP(s) requests. HTTP(s) services can be either:

A "local" service is one that is defined by the user and runs as a Docker container on the user's local environment or machine. The user is expected to provide the Docker Compose specification. These are services that your team owns.

An "external" service is one that isn't ran by the user directly such as services and APIs provided by other teams or third-party ones such as payment processors and other APIs. The user is expected to provide the hostname to this service's API.

### Core Services

Core services are automatically created as part of a scaffolded application. These include:

* `stoobly-agent` proxies - a proxy will be created per service
* A Stoobly UI - a single UI that can access your mock data across services
* Gateway - intelligently routes requests to the correct service

{% hint style="warning" %}
Core services or their configurations should not be modified.
{% endhint %}

### Workflow

A workflow belongs to a service and captures a specific use-case for it. Use cases include, but are not limited to recording, mocking, and testing requests.

When creating a service, the following workflows can be added:

* `mock` - used for mocking requests
* `record` - used for recording requests
* `test` - used for running a scaffolded application in CI or testing environments

## Next steps

{% content-ref url="/pages/tP6ceRL955iEhJFFSO2W" %}
[How to Scaffold an App](/guides/how-to-integrate-e2e-testing/how-to-scaffold-an-app)
{% endcontent-ref %}


# Service

A service can be a part of one or more workflows. When a workflow is run, only services that are a part of the workflow will be started.

## Properties

<details>

<summary>app-dir-path</summary>

Defaults to the current working directory. Configures where the scaffolded service files are created.

</details>

<details>

<summary>detached</summary>

Configures whether the `.stoobly` folder in the context directory path gets mounted. If the flag is set, a separate non-persistent Stoobly context gets created. The context directory path is specified when a workflow is run. To learn more see [here](/core-concepts/scaffold/workflow#core-workflows).

</details>

<details>

<summary>hostname</summary>

If a hostname for the service is specified, a proxy container will also be started when the service is instatiated as part of a workflow run.

</details>

<details>

<summary>priority</summary>

Configures the order which the service is run. Ranges from 0 to 10. If a service is configured with a priority of 0, then it will run before services with a greater priority value.

</details>

<details>

<summary>workflow</summary>

Configures which workflows the service belongs to, allowed values are `record` , `mock`, `test`. Defaults to no workflows.

</details>

## Containers

{% hint style="info" %}
To learn more about the purpose of each file, see [here](/core-concepts/scaffold/workflow#file-structure)
{% endhint %}

When service workflow is run, the following containers are started:

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-25f9602c8df9d036f01bd50615e5c40fab257d5c%2Fservice-containers.png?alt=media" alt=""><figcaption><p>Service containers and files they depend on</p></figcaption></figure>

### init

The init container is the first container that gets run when a service starts. If it fails, dependent containers will not run. The first script that runs is the maintained `.init` script which then runs the customizable `init` script. Only the `.init`script will be overriten when the application is re-scaffolded.

### proxy

{% hint style="info" %}
This container only runs if a `hostname` property is configured
{% endhint %}

The proxy container is the last container that gets run. It provides a `lifecycle_hooks.py`script that enables customization of requests and response at different points of their lifecycles. To learn more:

{% content-ref url="/pages/ANLbxIN4T0Q4YF2llfer" %}
[Lifecycle Hooks](/core-concepts/agent/lifecycle-hooks)
{% endcontent-ref %}

For `mock` and `test` workflows, the following are also provided:

* `fixtures.yml` enables mapping URL's to static responses stored in files. To learn more:

{% content-ref url="/pages/GOo6YjREp8psDDjix3k1" %}
[Fixtures](/core-concepts/mock-api/fixtures)
{% endcontent-ref %}

* `public` folder enables defining mock request paths and responses using files stored in this folder. To learn more:

{% content-ref url="/pages/NUSptr4JMkNbMKFeZPwz" %}
[Public Folder](/core-concepts/mock-api/public-folder)
{% endcontent-ref %}

### custom

Custom containers can be defined in the provided `docker-compose.yml`.

{% hint style="info" %}
The `profiles`and `networks` properties need to be set accordingly
{% endhint %}

## Core Services

Core services are services maintained by Stoobly and maintains the following start order:

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-87e847060c7364465fbd4d16a54e547a2337d08f%2Fcore-services.png?alt=media" alt=""><figcaption><p>Core services outlined in orange</p></figcaption></figure>

### build

Is the first service to be started and runs the [snapshot apply command](/guides/how-to-mock-apis/how-to-snapshot-requests/sharing-snapshots) to build mocks.

### gateway

Is responsible for routing requests from the host to the appropriate custom service.

### stoobly-ui

Provides a UI on <http://localhost:4200> to manage mocks and proxy configuration.

### entrypoint

Is the last service to be started and has the purpose of being extended in the provided `docker-compose.yml` with custom functionality.

## Get Started

{% content-ref url="/pages/BKCC6lKg9jOIW8EYkhK8" %}
[Scaffolding a Service](/guides/how-to-integrate-e2e-testing/how-to-scaffold-an-app/scaffolding-a-service)
{% endcontent-ref %}


# Validation

When we encounter an error after a scaffolded workflow is run, we want to diagnose the cause. Scaffold validation does the following checks on your application:

{% tabs %}
{% tab title="Record" %}

* Core services are running
* Containers for each service are running
* Resource directories are mounted within the containers
* Requests can be recorded from each service
* Stoobly UI is running and accessible on localhost port 4200
  {% endtab %}

{% tab title="Mock" %}

* Core services are running
* Containers for each service are running
* Resources are mounted within the containers
* Requests can be mocked from each service
* Stoobly UI is running and accessible on localhost port 4200
  {% endtab %}

{% tab title="Test" %}

* Core services are running
* Containers for each service are running
* Resources are mounted within the containers
* Requests can be mocked from each service
  {% endtab %}
  {% endtabs %}

## Core Services

| Service    | Record | Mock | Test |
| ---------- | ------ | ---- | ---- |
| build      | ✅      | ✅    | ✅    |
| entrypoint | ✅      | ✅    | ✅    |
| gateway    | ✅      | ✅    | ❌    |
| stoobly-ui | ✅      | ✅    | ❌    |

## Service Containers

A service is comprised of one or more containers and belongs to one or more worfklows. When a workflow is run, the following containers will be started:

<table><thead><tr><th width="251">Container</th><th>Detached</th><th>With Hostname</th><th>Without Hostname</th></tr></thead><tbody><tr><td>&#x3C;WORKFLOW>-init</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>&#x3C;WORKFLOW>-proxy</td><td>✅</td><td>✅</td><td>❌</td></tr></tbody></table>

## Resource Directory Mounts

<table><thead><tr><th width="169">Resource Directory</th><th width="269">Destination</th><th width="98">Detached</th><th>With/Without Hostname</th></tr></thead><tbody><tr><td>.stoobly</td><td>/home/stoobly/.stoobly</td><td>❌</td><td>✅</td></tr><tr><td>.stoobly/services</td><td>/home/stoobly/.stoobly/services</td><td>✅</td><td>✅</td></tr></tbody></table>

## Get Started

{% content-ref url="/pages/LmG9o2oN0VNqsBmYIhqz" %}
[Validating](/guides/how-to-integrate-e2e-testing/how-to-run-a-workflow/troubleshooting/validating)
{% endcontent-ref %}


# Workflow

A workflow groups configurations for services to perform distinct use cases. By default, Stoobly provides configurations for four workflows: record, mock, test, and develop. Use `--workflow` when creating a service to select a subset instead of all four (see the [Scaffold FAQ](/faq/scaffold) for details).

## Background

To learn more about the role of individual services, see:

{% content-ref url="/pages/CV2FP4ZBSIpH9GCwJxyX" %}
[Service](/core-concepts/scaffold/service)
{% endcontent-ref %}

To run a workflow, see:

{% content-ref url="/pages/7J10qWFxe9zweKA3YQtH" %}
[How to Run a Workflow](/guides/how-to-integrate-e2e-testing/how-to-run-a-workflow)
{% endcontent-ref %}

To validate a workflow, see:

{% content-ref url="/pages/mrxE2H3fxfCSRj8hF0QQ" %}
[Validation](/core-concepts/scaffold/validation)
{% endcontent-ref %}

## File Structure

{% hint style="info" %}
To learn how each file is used, see [here](/core-concepts/scaffold/service#containers).
{% endhint %}

{% hint style="warning" %}
Any hidden file will be overritten when the scaffold service create command is rerun.
{% endhint %}

<details>

<summary>bin/init</summary>

First script that executes when a workflow runs. Should contain any commands needed for the service to initialize. Can also contain configuration commands for Stoobly. See [filter rules](/core-concepts/agent/proxy-settings/filter-rules), [match rules](/core-concepts/agent/proxy-settings/match-rules), and [rewrite rules](/core-concepts/agent/proxy-settings/rewrite-rules).

</details>

<details>

<summary>bin/.init</summary>

Maintained file that will be overriden on scaffold create.

</details>

<details>

<summary>docker-compose.yml</summary>

Custom docker-compose.yml file. Container services defined in this should should include:

* Respective `<WORKFLOW-NAME>` under the `profiles` property
* Either `app.egress` or `app.ingress` under the `networks` property

</details>

<details>

<summary>.docker-compose.&#x3C;WORKFLOW-NAME>.yml</summary>

Maintained file that will be overriden on scaffold create.

</details>

<details>

<summary>fixtures.yml</summary>

Enables defining mock responses for specific URL patterns. To learn more see [here](/core-concepts/mock-api/fixtures).

</details>

<details>

<summary>lifecycle_hooks.py</summary>

Enables reading and modifying requests during specific points in their lifecycle. To learn more see [here](/core-concepts/agent/lifecycle-hooks).

</details>

<details>

<summary>public</summary>

Enables defining mock request paths and responses using files stored in this folder. To learn more see [here](/core-concepts/mock-api/public-folder).

</details>

## Core Workflows

### Record

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-194a8da31e3eacfcba02e84eb5d365e2ab29c8d5%2Frecord-workflow.png?alt=media" alt=""><figcaption><p>Flow diagram for recording requests</p></figcaption></figure>

The journey of a request:

1. A request gets sent from the host e.g. browser or cURL
2. Gets sent to the gateway service
3. Gateway service routes the request based on hostname
4. Request gets intercepted by Stoobly running as a proxy
   1. Lifecycle hooks get triggered
5. Stoobly reverse proxies the request to the local or external API
6. On response, Stoobly records the request to its respective `.stoobly`folder
   1. Lifecycle hooks get triggered

### Mock

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-017f049af3e77604497d0e51cc7da411f6ad156e%2Fmock-workflow.png?alt=media" alt=""><figcaption><p>Flow diagram for mocking requests</p></figcaption></figure>

The journey of a request:

1. A request gets sent from the host e.g. browser or cURL
2. Gets sent to the gateway service
3. Gateway service routes the request based on hostname
4. Request gets intercepted by Stoobly running as a proxy
   1. Lifecycle hooks get triggered
5. Stoobly mocks requests if it has been previously recorded. If the request is not found, it can conditionally reverse proxy the request to the local or external API
   1. Lifecycle hooks get triggered

### Test

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-0ca15beadde0545d726fb767c6bb14560c7d6541%2Ftest-workflow.png?alt=media" alt=""><figcaption><p>Flow diagram for testing an application that sends requests</p></figcaption></figure>

The journey of a request:

1. A request gets sent from the entrypoint service
2. Gateway service routes the request based on hostname
3. Request gets intercepted by Stoobly running as a proxy
   1. Lifecycle hooks get triggered
4. Stoobly mocks requests if it has been previously recorded. If the request is not found, it can conditionally reverse proxy the request to the local or external API
   1. Lifecycle hooks get triggered

### Develop

Unlike record, mock, and test, the develop workflow isn't about capturing or replaying fixed responses.

It's for working against a service's real hostname (e.g. an endpoint your app already calls in staging or production) while transparently redirecting requests to a local development server.

This redirection is driven by [rewrite rules](/core-concepts/agent/proxy-settings/rewrite-rules) generated from the service's configured upstream hostname, port, and scheme. Whenever a service's upstream configuration changes, resync its develop rewrite rules with:

```bash
stoobly-agent scaffold workflow rewrite develop
```

The journey of a request:

1. A request gets sent from the host e.g. browser or cURL
2. Gets sent to the gateway service
3. Gateway service routes the request based on hostname
4. Request gets intercepted by Stoobly running as a proxy
   1. Lifecycle hooks get triggered
5. Stoobly rewrites the request, redirecting it from the service's original upstream hostname, port, and scheme to the local development target defined by the synced rewrite rules
6. Stoobly reverse proxies the rewritten request to the local development server and returns its response to the host
   1. Lifecycle hooks get triggered

`develop` is created automatically along with record, mock, and test whenever you run `scaffold service create` without a `--workflow` filter:

```bash
# Creates record, mock, test, AND develop workflows for the service
stoobly-agent scaffold service create api

# To create only a subset, list the workflows you want explicitly
stoobly-agent scaffold service create api --workflow mock --workflow test

# Or add develop to an existing service that was scaffolded with a subset
stoobly-agent scaffold workflow create develop --template develop --service api
```


# How to Run the Agent

## Background

{% content-ref url="/pages/E4PZA1jU4PXM4qJyqKi8" %}
[Agent](/core-concepts/agent)
{% endcontent-ref %}

## Prerequisite

{% content-ref url="/pages/-Mar1-Gka-Tff3z\_01mG" %}
[Installing the Agent](/getting-started/installing-the-agent)
{% endcontent-ref %}

## Getting Started

The agent can be started either from the CLI or with Docker

{% content-ref url="/pages/Jdhz2jS8CtL7tMjvxRFZ" %}
[Run with CLI](/guides/how-to-run-the-agent/run-with-cli)
{% endcontent-ref %}

{% content-ref url="/pages/X3dxJ2ASRTiSnwlLK3j6" %}
[Run with Docker](/guides/how-to-run-the-agent/run-with-docker)
{% endcontent-ref %}

## Next Step

{% content-ref url="/pages/XRMveeqrNM5K07qs5H8k" %}
[How to Record Requests](/guides/how-to-record-requests)
{% endcontent-ref %}


# Run with CLI

## Running the Agent

To start the agent, run:

```bash
stoobly-agent run
```

The above command will expose the proxy on port 8080 and the UI on port 4200

{% hint style="info" %}

* If the proxy port conflicts, configure it with the `--proxy-port INTEGER` flag
* If the UI port conflicts, configure it with `--ui-port INTEGER` flag
  {% endhint %}

Then you should see output similar to this to indicate that the agent started up successfully:

```
[INFO] UI starting and listening at 0.0.0.0:4200
[INFO] Proxy starting with mode regular and listening at 0.0.0.0:8080
[INFO] Proxy not yet configured to record
```

For macOS users, because `stoobly-agent` is a proxy server, you might be prompted to accept incoming network connections . Click "Allow".


# Run with Docker

How to use run Stoobly with Docker

## Prerequisite

Docker must be installed. Refer to the official Docker install instructions [here](https://docs.docker.com/engine/install).

## Running the Agent

Start the Docker container with the following command:

{% tabs %}
{% tab title="Linux" %}

```bash
docker run \
    -p 8080:8080 \
    -p 4200:4200 \
    -v ~/.stoobly:/home/stoobly/.stoobly \
    stoobly/agent
```

{% endtab %}

{% tab title="macOS" %}

```bash
docker run -it \
    -p 8080:8080 \
    -p 4200:4200 \
    -v ~/.stoobly:/home/stoobly/.stoobly \
    stoobly/agent
```

{% endtab %}
{% endtabs %}

The above command will:

1. Download the `stoobly/agent` Docker image from [Docker Hub](https://hub.docker.com/r/stoobly/agent)
2. Start the proxy and UI server
3. Expose the proxy on port 8080 and the UI on port 4200

{% hint style="info" %}

* If the proxy port conflicts, configure it with the `--proxy-port INTEGER` option
* If the UI port conflicts, configure it with `--ui-port INTEGER` option
  {% endhint %}

{% hint style="info" %}
The command will also mount the `~/.stoobly` data directory from your host as a data volume to persist changes. If you don't want to persist changes then remove the `-v ~/.stoobly:/home/stoobly/.stoobly` Docker option
{% endhint %}

After running the command, you should see output similar to this to indicate that the agent started up successfully:

```
UI server listening at http://0.0.0.0:4200

Loading script /usr/local/lib/python3.14/site-packages/stoobly_agent/record.py
Proxy server listening at http://*:8080
```


# How to Configure the Agent

How to configure Stoobly to intercept HTTP(s) traffic

Before we can record or mock requests, they must first be intercepted by the [agent](/core-concepts/agent). To do this, we can either setup the agent as a forward or reverse proxy.

{% hint style="info" %}
Some applications have their own proxy configurations e.g. Docker. Please refer to the application's documentation when applicable.
{% endhint %}

## Configuration Setups

We support two different setups for intercepting requests:

### Reverse Proxy

{% hint style="info" %}

#### Recommended for Single Upstream API

{% endhint %}

Use a reverse proxy when you have **one upstream API service** to intercept. This is the simplest setup as it routes all traffic for a specific domain through Stoobly.

**Best for:**

* Single API service
* Simple, straightforward routing
* When you want all requests to a domain intercepted

{% content-ref url="/pages/m8Aq4lu4QUh2Pgdy8CJz" %}
[Reverse Proxy](/guides/proxy-configuration/reverse-proxy)
{% endcontent-ref %}

### Forward Proxy with Filter Rules

{% hint style="info" %}

#### Recommended for multiple services

{% endhint %}

Use a forward proxy with [filter rules](/core-concepts/agent/proxy-settings/filter-rules) when you need to intercept requests to **multiple different services** or want fine-grained control over which requests are intercepted.

**Best for:**

* Multiple upstream API services
* Selective request interception
* Applications that make requests to various domains
* When you need to filter or exclude specific requests

With filter rules, you can:

* Include or exclude specific URL patterns
* Filter by HTTP method (GET, POST, etc.)
* Apply rules to specific modes (record, mock, replay)
* Control which requests get intercepted

{% content-ref url="/pages/Mt1ajQr0lhGVkalZFgWv" %}
[Forward Proxy](/guides/proxy-configuration/forward-proxy)
{% endcontent-ref %}

{% content-ref url="/pages/qs8imD4qtRLHTxh0jvvY" %}
[Filter Rules](/core-concepts/agent/proxy-settings/filter-rules)
{% endcontent-ref %}

## Verifying Setup

To verify successful setup of the agent, send a requests and check the logs to see if it was intercepted. For example, send a request with `curl https://docs.stoobly.com`, then in the agent logs you should see:

```
127.0.0.1:36368: GET https://docs.stoobly.com/ HTTP/2.0
     << HTTP/2.0 200 OK 263k
```


# Forward Proxy

Configure the proxy to intercept outbound requests

## Configuration

### System Wide

Intercepting requests system-wide can be convenient, but has the chance of capturing unintended traffic. To intercept requests from a specific application, see the [following section](#per-terminal-session).

{% tabs %}
{% tab title="Mac" %}
{% hint style="warning" %}
This guide was written for macOS 15 Sequoia but should be similar for other versions
{% endhint %}

1. Open **System Preferences**, then click **Network**
2. Select the network service you use from the list on the left — for example, Ethernet or Wi-Fi
3. Click **Advanced...** on the bottom right
4. Select the **Proxies** tab
5. Check **Web Proxy (HTTP)** and/or optionally **Secure Web Proxy (HTTPS)**
6. For each checked protocol, under **Web Proxy Server** enter
   * `localhost` as the host
   * `8080` as the port
7. Click **OK** on the bottom right and then **Apply** on the bottom right
   {% endtab %}

{% tab title="Linux" %}
{% hint style="warning" %}
The guide was written for Ubuntu 24.04 LTS, but should be similar for other Linux distributions
{% endhint %}

1. Open **Settings**, then click **Network**
2. To the right side of the **Network Proxy** section, click the⚙️icon
3. Check **Manual**
4. Enter `localhost` as the host and `8080` as the port for one or both **HTTP Proxy** and **HTTPS Proxy**
   {% endtab %}
   {% endtabs %}

{% hint style="warning" %}
Don't forget to disable the above configuration when not in use :innocent:
{% endhint %}

### Per Terminal Session

{% hint style="info" %}
Optional if already configured system-wide
{% endhint %}

To proxy HTTP requests, set these environment variables:

```
export http_proxy=localhost:8080
export HTTP_PROXY=localhost:8080
```

To proxy HTTPS requests, set environment variables:

```
export https_proxy=localhost:8080
export HTTPS_PROXY=localhost:8080
```

To specify IP addresses or domain names to not proxy:

```
export no_proxy=localhost:1234
export NO_PROXY=localhost:1234
```


# Enable HTTPS Traffic

Configure the forward proxy to intercept HTTPS traffic

{% hint style="info" %}
The following is only required if both:

* The proxy is configured as a forward proxy
* Recording HTTPS traffic is desired
  {% endhint %}

To enable recording HTTPS traffic, we first must trust Stoobly agent to be a certificate authority. To do so, you will need to add the CA certificate generated by Stoobly as a trusted certificate authority.

## System Wide Configuration

{% hint style="info" %}
Some applications (e.g. browsers) will require additional specific configuration. Please refer to their documentation.
{% endhint %}

### Automated Setup

{% tabs %}
{% tab title="Mac" %}
In the terminal run the following command:

```
stoobly-agent ca-cert install
```

This installs the CA certificate under **System** in **Keychain Access**. To find the certificate file path, use:

```bash
stoobly-agent ca-cert show --format cer
```

{% endtab %}

{% tab title="Linux" %}
In the terminal run the following command:

```
stoobly-agent ca-cert install
```

This will run Linux distribution specific commands to install the CA cert. We currently support the following distributions:

* Debian based ones, such as Ubuntu
* RHEL based ones, such as CentOS
  {% endtab %}
  {% endtabs %}

### Manual Setup

{% tabs %}
{% tab title="Mac" %}

1. Get the certificate path:

   ```bash
   stoobly-agent ca-cert show --format cer
   ```

   This outputs the path to the certificate file (e.g. `~/.stoobly/ca_certs/mitmproxy-ca-cert.cer`).
2. Open **Keychain Access** and click the **+** button in the top left corner
3. Select the certificate file using the path from step 1
4. Double-click the newly added row **mitmproxy**
5. Click the dropdown next to **When using this certificate**, and select **Always Trust**
   {% endtab %}

{% tab title="Linux" %}

1. Get the certificate path:

   ```bash
   stoobly-agent ca-cert show --format pem
   ```

   This outputs the path to the certificate file (typically `~/.stoobly/ca_certs/mitmproxy-ca-cert.pem`).
2. Install the certificate for your Linux distribution using the certificate path from step 1:

   For Debian/Ubuntu-based distributions:

   ```bash
   sudo cp $(stoobly-agent ca-cert show --format pem) /usr/local/share/ca-certificates/mitmproxy-ca-cert.crt
   sudo update-ca-certificates
   ```

   For RHEL/CentOS-based distributions:

   ```bash
   sudo cp $(stoobly-agent ca-cert show --format pem) /etc/pki/ca-trust/source/anchors/mitmproxy-ca-cert.crt
   sudo update-ca-trust
   ```

{% endtab %}
{% endtabs %}

## Browser Configuration

Most browsers use the system certificate store, so after running `stoobly-agent ca-cert install`, Chrome, Edge, and Safari should automatically trust the CA certificate. Firefox uses its own certificate store and requires manual configuration.

{% tabs %}
{% tab title="Chrome / Edge" %}
Chrome and Edge use the system certificate store. After installing the CA certificate system-wide with `stoobly-agent ca-cert install`, these browsers should automatically trust it.

**Verification:**

1. Start Stoobly agent: `stoobly-agent run`
2. Configure your browser to use the proxy (see [Forward Proxy configuration](/guides/proxy-configuration))
3. Visit an HTTPS site (e.g., `https://example.com`)
4. If no certificate warning appears, the CA certificate is properly trusted

**If you see certificate warnings:**

* Ensure you ran `stoobly-agent ca-cert install` with administrator privileges
* Restart your browser after installing the certificate
* On macOS, verify the certificate is trusted in Keychain Access
  {% endtab %}

{% tab title="Firefox" %}
Firefox uses its own certificate store and requires manual import of the CA certificate.

1. Get the certificate path:

   ```bash
   stoobly-agent ca-cert show --format pem
   ```

   This outputs the path to the certificate file (typically `~/.stoobly/ca_certs/mitmproxy-ca-cert.pem`).
2. Open Firefox and navigate to certificate settings:
   * Go to **Settings** (or **Preferences**)
   * Search for "certificates" in the search bar
   * Click **View Certificates** under **Certificates**
3. Import the certificate:
   * Click the **Authorities** tab
   * Click **Import...**
   * Navigate to the certificate path from step 1 (use the full path)
   * Select the certificate file and click **Open**
4. Trust the certificate:
   * In the dialog that appears, check **Trust this CA to identify websites**
   * Click **OK**
5. Verify:
   * Start Stoobly agent: `stoobly-agent run`
   * Configure Firefox to use the proxy
   * Visit `https://example.com` - you should see no certificate warning

**Note:** You can also use `--format cer` if you prefer the `.cer` format:

```bash
stoobly-agent ca-cert show --format cer
```

{% endtab %}

{% tab title="Safari" %}
Safari uses the macOS system Keychain. After running `stoobly-agent ca-cert install`, Safari should automatically trust the certificate.

**Verification:**

1. Verify the certificate is installed in Keychain Access:
   * Open **Keychain Access**
   * Search for "mitmproxy" or "stoobly"
   * Ensure it shows **Trust** as "Always Trust"
2. If not trusted:
   * Double-click the certificate
   * Expand **Trust**
   * Set **When using this certificate** to **Always Trust**
   * Close the dialog
3. Restart Safari and test with an HTTPS site through the proxy
   {% endtab %}
   {% endtabs %}


# Reverse Proxy

Configure the proxy to intercept inbound requests

## Command

```
stoobly-agent run --proxy-mode reverse:<URL>
```

## Configuring /etc/hosts

To use a reverse proxy with a specific domain name, you need to modify your `/etc/hosts` file to point the domain to `localhost`. This allows your system to resolve the domain name to the reverse proxy instead of the actual server.

### Manual Configuration

Edit `/etc/hosts` (requires administrator privileges):

**On Linux/macOS:**

```bash
sudo nano /etc/hosts
```

Add entries for each domain you want to intercept:

```
127.0.0.1 example.com
127.0.0.1 api.example.com
::1       example.com
::1       api.example.com
```

**On Windows:**

1. Open Notepad as Administrator
2. Open `C:\Windows\System32\drivers\etc\hosts`
3. Add the same entries as shown above

### Example

If you're setting up a reverse proxy for `https://api.example.com`:

1. Add to `/etc/hosts`:

   ```
   127.0.0.1 api.example.com
   ::1       api.example.com
   ```
2. Run Stoobly with reverse proxy mode:

   ```bash
   stoobly-agent run --proxy-mode reverse:https://api.example.com
   ```
3. Access the domain - requests will be intercepted:

   ```bash
   curl https://api.example.com/users
   ```

### Cleanup

Remember to remove entries from `/etc/hosts` when you're done testing, or comment them out by adding `#` at the start of each line.

{% hint style="info" %}
For scaffold workflows, you can use `stoobly-agent scaffold hostname install --workflow <WORKFLOW_NAME>` to automatically manage `/etc/hosts` entries for service hostnames.
{% endhint %}

## Enabling HTTPS Traffic

To enable HTTPS traffic to the reverse proxy, add the following options to the run command:

```
  --certs TEXT                    SSL certificates of the form
                                  "[domain=]path". The domain may include a
                                  wildcard, and is equal to "*" if not
                                  specified. The file at path is a certificate
                                  in PEM format. If a private key is included
                                  in the PEM, it is used, else the default key
                                  in the conf dir is used. The PEM file should
                                  contain the full certificate chain, with the
                                  leaf certificate as the first entry. May be
                                  passed multiple times.

  --cert-passphrase TEXT          Passphrase for decrypting the private key
                                  provided in the --cert option. Note that
                                  passing cert_passphrase on the command line
                                  makes your passphrase visible in your
                                  system's process list. Specify it in
                                  config.yaml to avoid this.
```


# How to Record Requests

Overview of recording HTTP(s) requests

This page provides a guide on how to configure the [agent](/core-concepts/agent) to create cequests.

## Background

{% content-ref url="/pages/-MaqwgidRyGQ24EvuqhN" %}
[Request](/core-concepts/mock-api/requests)
{% endcontent-ref %}

## Prerequisites

1. [Run the agent](/guides/how-to-run-the-agent)
2. [Configure the agent](/guides/proxy-configuration)

## Getting Started

### Create a Scenario

{% hint style="info" %}
This step is optional but recommended
{% endhint %}

{% content-ref url="/pages/Ip67YLrIJPaMa2nYPcu9" %}
[How to Create Scenarios](/guides/how-to-record-requests/how-to-create-scenarios)
{% endcontent-ref %}

### Record Requests

Requests can be recorded from either the UI or the CLI:

{% content-ref url="/pages/fgAO4oY4FlFFm2oTwo7M" %}
[Recording from the UI](/guides/how-to-record-requests/recording-from-the-ui)
{% endcontent-ref %}

{% content-ref url="/pages/PG4xazN8qThJoXYDqZu9" %}
[Recording from the CLI](/guides/how-to-record-requests/recording-from-the-cli)
{% endcontent-ref %}

### Configure Recording

By default, no additional configuration is needed. However, to configure recording to specific needs, please see:

{% content-ref url="/pages/gYoBO8SZbwJ5l7kqvbFc" %}
[Proxy Settings](/core-concepts/agent/proxy-settings)
{% endcontent-ref %}

### Send Requests

The following are some suggested ways to send requests to for Stoobly to intercept and record:

* Navigate to your application's web interface
* Send requests with cURL
* Run existing test suites

After sending requests, they are intercepted by the agent and then recorded. You should then see the requests appear in the Stoobly UI.

## Next Steps

{% tabs %}
{% tab title="API Mocking" %}
{% content-ref url="/pages/ZoO8T7nQGg9HF89Yvw3J" %}
[How to Mock APIs](/guides/how-to-mock-apis)
{% endcontent-ref %}
{% endtab %}

{% tab title="E2E Testing" %}
{% content-ref url="/pages/Ri9aZJJVXgxuyy67a3tW" %}
[How to Integrate E2E Testing](/guides/how-to-integrate-e2e-testing)
{% endcontent-ref %}
{% endtab %}

{% tab title="Replaying" %}
{% content-ref url="/pages/dIUPn1yuexQAeM7ODum5" %}
[How to Replay Requests](/guides/how-to-replay-requests)
{% endcontent-ref %}
{% endtab %}
{% endtabs %}


# Recording from the UI

## Recording Requests

1. Visit the UI at [http://locahost:4200](http://locahost:4200/projects).

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-86c39ff88af340f4e8b6c49410a4ae60bd5544b4%2FScreen%20Shot%202023-04-05%20at%204.02.52%20PM.png?alt=media" alt=""><figcaption><p>Figure 1. Requests page with no recorded requests</p></figcaption></figure>

2. (Recommended) [Configure a scenario to record requests to](#scenario-configuration).
3. On the top left of the screen, click the **Run** button.

<div align="left"><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-9a306846a87d90b5448258cf00d9b252bf54a35e%2Frecord-button.png?alt=media" alt="Figure 2. Agent UI navigation menu" width="339"></div>

The figure below indicates that recording has started.

<div align="left"><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-e219617676df8e582f587204143265233f90d056%2FScreen%20Shot%202023-04-05%20at%204.14.45%20PM.png?alt=media" alt="Figure 3. Agent set to record requests" width="362"></div>

4. If the system proxy was [configured](/guides/proxy-configuration) properly to forward requests to our agent, you should now see requests appear in the requests page! You can now:

* Open up a new browser tab and visit your favorite webpage.
* Alternatively you can also use any HTTP client tool to send a request such as with `cURL`.

![Figure 4. Requests page with one recorded request](https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-d3f57b804f00fbc566a573b001373cdd6788ffa6%2FScreen%20Shot%202023-04-05%20at%204.16.40%20PM.png?alt=media)

## Scenario Configuration

Recording to a scenario is not required, but highly recommended.

1. Visit <http://localhost:4200/agent/proxy-settings>.

<div align="left"><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-af3369a872fc01985375a4b91e023ae61e4f8b5f%2FScreen%20Shot%202023-04-05%20at%204.10.07%20PM.png?alt=media" alt="Figure 5. Record General Settings"></div>

2. Set **Source or Destination** to a scenario.

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-8ef3d1a6d3f2487b57770ec869cfdd77fb664092%2FScreen%20Shot%202023-04-05%20at%204.26.55%20PM.png?alt=media" alt=""><figcaption><p>Figure 8. How to set the destination to your scenario</p></figcaption></figure>


# Recording from the CLI

## Recording Requests

The basic method for recording requests uses the intercept commands directly:

### Command

```bash
stoobly-agent intercept set --mode record
stoobly-agent intercept enable
```

### Options

To see more options for the command:

```sh
$ stoobly-agent intercept set -h

```

```
Usage: stoobly-agent intercept set [OPTIONS]

  Configure intercept

Options:
  --mode [mock|record|replay]
  --policy [all|found]
  -h, --help                   Show this message and exit.
```

## Recording with Scaffold Workflows

When using Stoobly scaffold for E2E testing or multi-service setups, you can record requests using scaffold workflows. The approach differs based on your runtime:

### Docker Runtime

For Docker runtime, use Makefile commands to run the record workflow:

```bash
# Start the record workflow
make -f .stoobly/services/Makefile record

# Enable intercept to start recording
make -f .stoobly/services/Makefile intercept/enable

# Stop the workflow
make -f .stoobly/services/Makefile record/down
```

**Note:** With Docker runtime and E2E testing, your tests typically run automatically in the entrypoint container, and all HTTP requests are recorded.

### Local Runtime

For local runtime, use CLI commands directly:

```bash
# Start the record workflow
stoobly-agent scaffold workflow up record

# Enable intercept to start recording
stoobly-agent intercept enable

# In another terminal, configure your application to use the proxy
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080

# Run your application or tests
# Requests will be intercepted and recorded

# View recorded requests
stoobly-agent request list

# Stop the workflow
stoobly-agent scaffold workflow down record
```

**Note:** Make commands (e.g., `make -f .stoobly/services/Makefile record`) are Docker-specific only. Local runtime uses `stoobly-agent scaffold workflow up/down` commands directly.

### Additional Recording Options

You can configure recording behavior using intercept options:

```bash
# Record all requests (default)
stoobly-agent intercept set --mode record --policy all

# Record only new requests (skip already recorded ones)
stoobly-agent intercept set --mode record --policy not_found

# Record with full strategy (complete request/response data)
stoobly-agent intercept set --mode record --strategy full

# Overwrite existing recordings
stoobly-agent intercept set --mode record --order overwrite
```

For more details on scaffold workflows, see:

{% content-ref url="/pages/7J10qWFxe9zweKA3YQtH" %}
[How to Run a Workflow](/guides/how-to-integrate-e2e-testing/how-to-run-a-workflow)
{% endcontent-ref %}


# How to Create Contexts

## Background

{% hint style="info" %}
While not required, creating separate contexts is recommended. Otherwise the default context from your home directory will be used and will be where the snapshots get saved to. Creating a new context can be useful for separating snapshots in different code repositories.
{% endhint %}

{% content-ref url="/pages/Wb3dRkgNwOa7tF9dOXcx" %}
[Context](/core-concepts/context)
{% endcontent-ref %}

## Creating Contexts

{% hint style="info" %}
Creating contexts is only supported with the CLI
{% endhint %}

In your terminal, change directories to the one you want to create a new context in. Then run:

```bash
stoobly-agent init
```

This command will create an empty `.stoobly` directory. Next execute the run command with any flags as desired:

```bash
stoobly-agent run
```

Afterwards the `.stoobly` directory will contain an empty local database and other default configuration needed for a new Context. Now if you view requests in either the UI or CLI, you'll notice there is no data.


# How to Create Scenarios

Overview of creating scenarios

This page provides a guide on how to create Stoobly Scenarios.

## Background

{% content-ref url="/pages/-MaqwgidRyGQ24EvuqhN" %}
[Request](/core-concepts/mock-api/requests)
{% endcontent-ref %}

{% content-ref url="/pages/-MaqwD0Jo7DUdY95\_N3w" %}
[Scenarios](/core-concepts/mock-api/scenarios)
{% endcontent-ref %}

## Prerequisites

1. [Install the agent](/getting-started/installing-the-agent)

## Creating a Scenario

A scenario can be created from either the UI or the CLI:

{% content-ref url="/pages/xglcrCBgjHoadxMKQvrw" %}
[Creating from the UI](/guides/how-to-record-requests/how-to-create-scenarios/creating-from-the-ui)
{% endcontent-ref %}

{% content-ref url="/pages/lycztZNFepbfbJCBxGJD" %}
[Creating from the CLI](/guides/how-to-record-requests/how-to-create-scenarios/creating-from-the-cli)
{% endcontent-ref %}

## Notes

{% hint style="info" %}
Newly created scenarios will have no requests inside.

See our guides on [How to Record Requests](/guides/how-to-record-requests) to learn how to populate scenarios.
{% endhint %}


# Creating from the UI

## Creating Requests

1. Visit <http://localhost:4200/agent/scenarios>.
   * Or from any page, click on the scenarios tab on the left navigation bar:

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-ce0f67ff1b660923c61d3660b01a5bd5a8bec10d%2FScreen%20Shot%202023-04-05%20at%204.02.52%20PM%20copy.png?alt=media" alt=""><figcaption><p>Figure 1. How to get to the Scenarios page</p></figcaption></figure>

2. Click on the **CREATE** button on the top left corner.

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-eeebc3a897fba0d888f9654b5c29192a46df65eb%2Fscenarios-index-create.PNG?alt=media" alt=""><figcaption><p>Figure 2. Scenarios Create Button</p></figcaption></figure>

3. Then provide a **name** and a **description** (optional).

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-b6e182ab428f5e78f94562ae5ad1ad9a31381c1e%2FScreen%20Shot%202023-04-05%20at%204.24.06%20PM.png?alt=media" alt=""><figcaption><p>Figure 3. Create your Scenario</p></figcaption></figure>

3. Finally click the **CREATE** button on the bottom right of the prompt.


# Creating from the CLI

## Creating a Scenario

### Command

```bash
stoobly-agent scenario create --description "<DESCRIPTION>" "<NAME>"
```

### Options

To see more options for the command:

```sh
$ stoobly-agent scenario create --help
```

```
Usage: stoobly-agent scenario create [OPTIONS] NAME

  Create a scenario

Options:
  --description TEXT  Scenario description.
  --select TEXT       Select column(s) to display.
  --without-headers   Disable printing column headers.
  -h, --help          Show this message and exit.
```

This command has additional flags such as `--select COLUMN` and `--without-headers` to customize the stdout displayed after the command gets run. This is useful for programmatic usage such as in CI pipelines.


# How to Create Requests

The following are methods to manually create a request either through the UI or CLI.

## Method 1: UI

Navigate to the requests page and click on the **CREATE** button on the top left corner.

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-fc75216fda30d4eca58a35119416b28c398145f6%2Frequests-index-create.PNG?alt=media" alt=""><figcaption><p>Requests Create</p></figcaption></figure>

## Method 2: Record

With the CLI, run the following command to record a request.

```bash
$ stoobly-agent record <URL>
```

## Method 3: Replay and Record

With the CLI, run the following command to replay an existing request and save it to a new request.

```bash
$ stoobly-agent request replay --record <REQUEST_KEY>
```


# How to Customize Recordings

##


# Customizing with Lifecycle Hooks

## Background

{% content-ref url="/pages/ANLbxIN4T0Q4YF2llfer" %}
[Lifecycle Hooks](/core-concepts/agent/lifecycle-hooks)
{% endcontent-ref %}

## Writing a Lifecycle Hooks Script

1. Write a Python script (e.g. lifecycle\_hooks.py)
2. In this script, define the lifecycle events to hook into
3. Define what kind of behavior to execute for each of those events

Below is a sample script that prints some strings during two lifecycle events.

{% hint style="warning" %}
Manipulating the **context** object will affect the behaviour of the request interception.
{% endhint %}

```python
from stoobly_agent.app.proxy.context import InterceptContext
from stoobly_agent.app.proxy.record.context import RecordContext

def handle_before_request(context: InterceptContext):
    print('Before request!')

def handle_before_record(context: RecordContext):
    print('Before record!')
```

* `handle_before_request` is for **before** a request gets sent
* `handle_before_record` is for **before** a request gets recorded

After a request gets intercepted, the string `"Before request!"` will be printed. After the response returns, but before the request gets recorded, `"Before record!"` will be printed.

## Enabling Lifecycle Hook Script Use

Pass the path to the lifecycle hooks scripts using the `--lifecycle-hooks-path` option:

```bash
stoobly-agent run --lifecycle-hooks-path ~/path-to-file/lifecycle_hooks.py
```

## Example

```python
from stoobly_agent.app.proxy.record.context import RecordContext

def handle_before_record(context: RecordContext):
    request = context.flow.request
    respose = context.flow.response
    
    request.headers['Authorization'] = '<REDACTED>'
    request.headers['Cookie'] = ''
    
    response.headers['Set-Cookie'] = ''
```


# How to Update Requests

## Prerequisites

1. [Run the agent](/guides/how-to-run-the-agent)
2. [Configure the proxy](/guides/proxy-configuration)
3. [Record request(s)](/guides/how-to-record-requests)

## Why Update Requests?

At some point in time, API providers will change the contract of a request. For example, maybe a component in the request or its response needs to be updated. When this happens we should also update the Stoobly request.

## Updating Requests

{% hint style="warning" %}
Before updating a request, it is recommended to create a [snapshot](/core-concepts/mock-api/snapshots) in case changes need to be reverted.
{% endhint %}

There are three main strategies to update request(s):

### Editing

* [Edit individual requests from the UI](/guides/how-to-update-requests/editing-from-the-ui)
* [Edit request snapshots](/guides/how-to-update-requests/editing-with-snapshots)

### Replaying

* [Replay individual requests](/guides/how-to-replay-requests)
* [Replay scenarios](/guides/how-to-update-requests/how-to-update-scenarios/updating-with-replay)

### Overwriting

* [Overwriting scenarios](/guides/how-to-update-requests/how-to-update-scenarios/updating-with-overwrite)

## Persisting Changes

{% content-ref url="/pages/Tyk5SmKa5es0I3YjLQA0" %}
[How to Snapshot Requests](/guides/how-to-mock-apis/how-to-snapshot-requests)
{% endcontent-ref %}

## Reverting Changes

In case you update a request with unintended consequences, you can reset it to the last snapshot state. For more information see our documentation on the snapshots feature:

{% content-ref url="/pages/WFKkQFPE0l9Zauwmdgd6" %}
[Snapshots](/core-concepts/mock-api/snapshots)
{% endcontent-ref %}

### Command

```bash
stoobly-agent request reset "<REQUEST-KEY>"
```

### Options

```bash
$ stoobly-agent request reset --help

Usage: stoobly-agent request reset [OPTIONS] REQUEST_KEY

  Reset a request to its snapshot state

Options:
  --force     Toggles whether resources are hard deleted.
  -h, --help  Show this message and exit.
```


# Editing from the UI

## Updating a Request by Editing

{% stepper %}
{% step %}
Navigate to the requests list page

[http://localhost:4200/agent/requests](http://localhost:4201/agent/requests)
{% endstep %}

{% step %}
Right click on the request we want to edit and click 'Edit'

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-6f66a2c08944e536b99b84ddcea0edf015a295ea%2Frequest-edit-dropdown.png?alt=media" alt=""><figcaption></figcaption></figure>
{% endstep %}

{% step %}
Clicking on one of the following buttons to edit the respective property

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-27dd1a3bf0dfcb8a3f7888efee8032ec0ecfaa0e%2Frequest-edit-details.png?alt=media" alt=""><figcaption></figcaption></figure>
{% endstep %}

{% step %}
A prompt should pop up. Edit as needed and click 'UPDATE'

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-270c2c34ec6d1b3e25eca0de315ddcf84fc39395%2Frequest-edit-prompt.png?alt=media" alt=""><figcaption></figcaption></figure>
{% endstep %}

{% step %}
**(Optional) Persist the updated request with a snapshot**

If you want to version control or share the updated request, create a snapshot:

```bash
stoobly-agent request snapshot "<REQUEST-KEY>"
```

You can copy the request key from the request details page. For more information, see [how to snapshot requests](/guides/how-to-mock-apis/how-to-snapshot-requests).
{% endstep %}
{% endstepper %}


# Editing with Snapshots

## Prerequisites

1. [Snapshot requests](/guides/how-to-mock-apis/how-to-snapshot-requests)
2. (Optional) Use a version tool such as Git to backup changes

## Updating Requests by Editing Snapshots

{% stepper %}
{% step %}
**Find request snapshots that match a pattern**

Run the following CLI command:

```bash
stoobly-agent snapshot list --search <PATTERN> --select snapshot --select uuid
```

For example:

```bash
$ stoobly-agent snapshot list --search /api --select snapshot --select uuid
snapshot                                                             uuid
.stoobly/snapshots/requests/19/19cfd765-80bc-4a2c-ad36-c59e7dbb9c92  cd99c578-3a97-11f0-98ef-51122b0b22b6
```

{% endstep %}

{% step %}
**Edit request snapshots**

For each file found, make the desired change to the request snapshot.

In the example from step 1, the request snapshot is stored in `.stoobly/snapshots/requests/19/19cfd765-80bc-4a2c-ad36-c59e7dbb9c92` .
{% endstep %}

{% step %}
**Create new snapshots for each updated request**

Run the following CLI command:

```bash
stoobly-agent snapshot update <SNAPSHOT-UUID>
```

In the example from step 1, the snapshot uuid is `cd99c578-3a97-11f0-98ef-51122b0b22b6`.
{% endstep %}

{% step %}
**Apply the snapshots**

Run the following CLI command:

```
stoobly-agent snapshot apply
```

{% endstep %}
{% endstepper %}


# How to Update Scenarios

## Prerequisites

1. [Run the agent](/guides/how-to-run-the-agent)
2. [Configure the proxy](/guides/proxy-configuration)
3. [Record requests to a scenario](/guides/how-to-record-requests)

## Why Update Scenarios?

API flows change over time. That is, the composition of a request within the scenario may change e.g. a request may require a new query param. When this happens we need to update the Stoobly to receive the latest updates. This is done in three high-level steps:

1. Configure a scenario to be overwritable
2. Enable recording
3. Manually triggering the scenario or using a test to replay requests

Afterwards, the scenario will be available for use and will contain all the updated requests.

## Updating Scenarios

{% hint style="warning" %}
Before updating a scenario, it is recommended to create a [snapshot](/core-concepts/mock-api/snapshots) in case changes need to be reverted.
{% endhint %}

There are two ways to update scenarios, from the UI and from the CLI:

{% content-ref url="/pages/o4RRhPsOcJxoLkgmRf6u" %}
[Updating with Overwrite](/guides/how-to-update-requests/how-to-update-scenarios/updating-with-overwrite)
{% endcontent-ref %}

{% content-ref url="/pages/WAbcT9cgXCNJHgOIFP0z" %}
[Updating with Replay](/guides/how-to-update-requests/how-to-update-scenarios/updating-with-replay)
{% endcontent-ref %}

The first request that gets recorded will overwrite the scenario. Any future recorded request will be appended.

## Persisting Changes

After updating a scenario, you should create a snapshot to persist the changes. This uses the **scenario-specific** snapshot command:

```bash
stoobly-agent scenario snapshot "<SCENARIO-KEY>"
```

For more details on snapshotting, see:

{% content-ref url="/pages/Tyk5SmKa5es0I3YjLQA0" %}
[How to Snapshot Requests](/guides/how-to-mock-apis/how-to-snapshot-requests)
{% endcontent-ref %}

{% hint style="info" %}
**Note:** There are two different snapshot commands:

* `stoobly-agent request snapshot "<REQUEST-KEY>"` - For snapshotting individual requests
* `stoobly-agent scenario snapshot "<SCENARIO-KEY>"` - For snapshotting entire scenarios
  {% endhint %}

## Reverting Changes

Sometimes you need to revert changes such as when you accidentally record wrong requests to the scenario or overwrite data unintentionally.

Instead of experiencing data loss or corruption, you can reset the scenario back to it's previous snapshotted state.

For more information see our documentation on the snapshots feature:

{% content-ref url="/pages/WFKkQFPE0l9Zauwmdgd6" %}
[Snapshots](/core-concepts/mock-api/snapshots)
{% endcontent-ref %}

### Command

```bash
stoobly-agent scenario reset
```

### Options

```bash
$ stoobly-agent scenario reset --help

Usage: stoobly-agent scenario reset [OPTIONS] SCENARIO_KEY

  Reset a scenario to its snapshot state

Options:
  --force     Toggles whether resources are hard deleted.
  -h, --help  Show this message and exit.
```


# Updating with Overwrite

## Background

{% content-ref url="/pages/WGDfUf8LR718Ltv79uSX" %}
[How to Update Scenarios](/guides/how-to-update-requests/how-to-update-scenarios)
{% endcontent-ref %}

## Overwriting

The following will overwrite the scenario with newly recorded requests and their respective responses.

{% tabs %}
{% tab title="CLI" %}
**Steps**

1. Select the scenario you want to overwrite. To select the scenario, set the [scenario key](/core-concepts/mock-api/scenarios#scenario-key):

```bash
stoobly-agent setting scenario "<SCENARIO_KEY>"
```

2. Set the Agent to **record** mode with **overwrite** policy.

```bash
stoobly-agent intercept set --mode record --policy overwrite
```

3. Enable request interception with the Agent.

```bash
stoobly-agent intercept enable
```

4. Replay the scenario either by trigging requests from the application or rerunning a test to verify that the overwrite behaves as expected.
5. (Optional) Persist the changes with a snapshot to commit the updates to version control:

```bash
stoobly-agent scenario snapshot "<SCENARIO_KEY>"
```

This allows you to:

* Version control your updated scenario via Git
* Share the updates with your team
* Revert to this snapshot if needed later
  {% endtab %}

{% tab title="UI" %}
In the **Proxy Settings** go to the **Data** section.

1. Set a scenario
2. For the **Record Policy**, choose **overwrite**. Then click the **Update** button at the bottom
3. Finally set the **Proxy Mode** at the top left to **Record** and click the **Run** button to start intercepting requests

Below is a screenshot showing what the UI configuration will look like:

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-60283f82eac961fee30ee458e312900b5d40aab5%2Fupdate-scenario-record-overwrite.png?alt=media" alt=""><figcaption></figcaption></figure>

4. (Optional) Persist the changes with a snapshot if you want the updates committed to version control:

```bash
stoobly-agent scenario snapshot "<SCENARIO_KEY>"
```

This allows you to:

* Version control your updated scenario via Git
* Share the updates with your team
* Revert to this snapshot if needed later
  {% endtab %}
  {% endtabs %}

## Cleanup

After overwriting your scenario successfully, you can disable intercepting requests with the Agent with the following command:

```bash
stoobly-agent intercept disable
```

You can also update your scenario key back to what it was before or you can clear it out so the Agent will not use any scenario. To clear the active scenario, run the following command:

```bash
stoobly-agent setting scenario clear
```


# Updating with Replay

There are two ways to update a scenario using the CLI.

* Replay a scenario's requests and update the request responses
* Overwrite the scenario with new requests and responses

## Background

{% content-ref url="/pages/WGDfUf8LR718Ltv79uSX" %}
[How to Update Scenarios](/guides/how-to-update-requests/how-to-update-scenarios)
{% endcontent-ref %}

## Replaying

{% hint style="warning" %}
If request(s) require authorization headers, they should be added dynamically.
{% endhint %}

The following command will replay the scenario and update the recorded responses with the newly received repsonses.

### Steps

{% stepper %}
{% step %}
**Decorate requests with credentials**

An authorization header or a cookie may be needed to be added to replayed requests. To do so, see the following guide on how to use [lifecycle hooks](/guides/how-to-update-requests/updating-with-replay/how-to-customize-replays/customizing-with-lifecycle-hooks).
{% endstep %}

{% step %}
**Replay the scenario**

```bash
stoobly-agent scenario replay --overwrite "<SCENARIO-KEY>"
```

{% endstep %}

{% step %}
**(Optional) Persist changes with a snapshot**

If you want to version control or share the updated scenario, create a snapshot:

```bash
stoobly-agent scenario snapshot "<SCENARIO-KEY>"
```

This allows you to:

* Version control your updated scenario via Git
* Share the updates with your team
* Revert to this snapshot if needed later
  {% endstep %}
  {% endstepper %}


# Updating with Replay


# Replaying from the UI

## Updating a Request by Replaying

1. Navigate to the requests list page at [http://localhost:4200/agent/requests](http://localhost:4201/agent/requests)
2. Click on the request that we want to update. In the screenshot, we see a request that returned a 200 status code and a healthy json body in the response. For our example, this is a HTTP request to an application running on `localhost` that then calls the Spotify's API to return details about a song.

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-f3e6f37bba1cb0e9d771d4fdc30f457a71e35c2f%2FScreenshot%202023-05-03%20141009.png?alt=media" alt=""><figcaption><p>Request details</p></figcaption></figure>

3. Now go to the Replay History by clicking on the following tab

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-65ab057fbcd3be99224f639b04a0ff3e929e9922%2FScreenshot%202023-05-03%20143454%20-%20Copy%20(2).png?alt=media" alt=""><figcaption><p>Replay History tab</p></figcaption></figure>

4. Pick one of the requests to overwrite the current HTTP response with and click on "Activate"

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-b9a51d2ea7102909b9c193e3413414bf3ec5adee%2FScreenshot%202023-05-03%20144826.png?alt=media" alt=""><figcaption><p>Activate button</p></figcaption></figure>

5. A prompt should pop up asking you to confirm. Click on "CONFIRM"

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-e034bc7158ec8d7dfb7b54b3a7f6b81b03040755%2FScreenshot%202023-05-03%20144845.png?alt=media" alt=""><figcaption><p>Confirm</p></figcaption></figure>

6. The response for the request has now been updated successfully!

<figure><img src="https://3980092275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLvhXOE-py5MDUOXDKD%2Fuploads%2Fgit-blob-d7db6c81d308bc5c17e225e8111ee839f1777dcc%2FScreenshot%202023-05-03%20144901.png?alt=media" alt=""><figcaption><p>Success!</p></figcaption></figure>

7. Finally, run the Agent in Mock mode and send a HTTP request to that endpoint. After sending a request, Stoobly will return the new response instead of the old one. Please note that you can change the response back to its original one or any of the re-recordings by using the [Replay History](/core-concepts/mock-api/requests/replay-history).


# Replaying from the CLI

## Updating a Request by Replaying

### Command

```bash
stoobly-agent request replay --overwrite "<REQUEST-KEY>"
```

## Updating Multiple Requests by Replaying

1. Grab the key of all the requests that need updating

```bash
request_keys=$(stoobly-agent request list --search "<SEARCH-PHRASE>" --select key --without-headers)
```

The search option will match either by the request's hostname or path. Currently regex is not supported.

2. Pass each request key to the replay command

```bash
echo $request_keys | xargs stoobly-agent request replay --overwrite
```


# How to Customize Replays

##


# Customizing with Lifecycle Hooks

## Background

{% content-ref url="/pages/ANLbxIN4T0Q4YF2llfer" %}
[Lifecycle Hooks](/core-concepts/agent/lifecycle-hooks)
{% endcontent-ref %}

## Writing a Lifecycle Hooks Script

1. Write a Python script (e.g. lifecycle\_hooks.py)
2. In this script, define the lifecycle events to hook into
3. Define what kind of behavior to execute for each of those events

Below is a sample script that prints some strings during two lifecycle events.

{% hint style="warning" %}
Manipulating the **context** object will affect the behaviour of the request interception.
{% endhint %}

```python
from stoobly_agent.app.proxy.replay.context import ReplayContext

def handle_before_replay(context: ReplayContext):
    print('Before replay!')

```

After a request gets intercepted, the string `"Before replay!"` will be printed.

## Enabling Lifecycle Hook Script Use

Pass the path to the lifecycle hooks scripts using the `--lifecycle-hooks-path` option:

```bash
stoobly-agent run --lifecycle-hooks-path ~/path-to-file/lifecycle_hooks.py
```

## Example

```python
from stoobly_agent.app.proxy.replay.context import ReplayContext
from stoobly_agent.config.constants import record_policy, replay_policy

def handle_before_replay(context: ReplayContext):
    intercept_settings = context.intercept_settings
    flow = context.flow
    headers = flow.request
    request = request.headers
    
    is_overwriting = intercept_settings.policy == record_policy.OVERWRITE
    if is_overwriting:
        # Handle setting credentials here
        # e.g. headers['authorization'] = '<TOKEN>'
        pass
```


# Updating with OpenAPI

{% hint style="warning" %}
This feature is experimental
{% endhint %}

## Supported Versions and Formats

We currently support [OpenAPI v3.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md) and [OpenAPI v3.1](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md).

Only the **json** and **yaml** versions of OpenAPI are currently supported.

## Updating Requests

1. Have your specification file ready on your local filesystem and make sure it is valid and compliant with your specification.
2. Go into a directory using the [Context](/core-concepts/context) you want to update the requests in.
3. Let's take a look at the relevant command:

```bash
$ stoobly-agent endpoint apply --help
Usage: stoobly-agent endpoint apply [OPTIONS] PATH

  Apply endpoint to requests

Options:
  --format [openapi]              File format  [required]
  --scenario-key TEXT             Which scenario requests to apply the endpoint to. If none then
                                  the endpoint will be applied to all requests.

  --lifecycle-hooks-script-path TEXT
                                  Path to lifecycle hooks script.
  -h, --help                      Show this message and exit.
```

By using the different flags and options, you can change what API format to use, which scenario if any to import into, as well as other features.

Here is an example command you can run after changing the PATH to your specification file:

```bash
$ stoobly-agent endpoint apply --format open-api ~/Downloads/your-spec-file.yaml
```

4. View your requests and you should see them updated.


# How to Mock APIs

## Background

{% content-ref url="/pages/diuAccWeQjVUcm58JWDS" %}
[Mock API](/core-concepts/mock-api)
{% endcontent-ref %}

## Prerequisite

{% content-ref url="/pages/XRMveeqrNM5K07qs5H8k" %}
[How to Record Requests](/guides/how-to-record-requests)
{% endcontent-ref %}




---

[Next Page](/llms-full.txt/1)

