# Context and the /context endpoint

> Write the context.md files that explain a workflow connector and its modules to Stacksync's AI, and read them back from the /context endpoints.

Source: https://docs.stacksync.com/developers/stacksync-cdk/context

Stacksync's AI builds and fixes workflows for users. To use your connector, it needs to know what each module does, what its inputs mean and what it returns. It learns this from the connector's `context.md` files, which the CDK serves at the `/context` endpoints.

A module with a clear `context.md` gets chosen, filled in and wired correctly by the AI. Write it for a capable colleague who has never seen your code: in the third person, concretely, with real field ids and real error messages.

Context is required. Stacksync refuses to deploy a connector while a required section is missing, empty or still contains `TODO`.

## Two files, two endpoints

| File                               | Endpoint                     | Describes                                                                                                                                              |
| ---------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `context.md` at the connector root | `GET /context`               | The connector: the system, its connection, its objects and the limits that apply to every module. Stacksync adds it in front of each module's context. |
| `modules/<module>/v<N>/context.md` | `GET /<module>/v<N>/context` | One version of one module. Most of the content goes here.                                                                                              |

Each module version has its own `context.md`, so `v2` can describe different inputs from `v1`. Update the file whenever you change the module.

## The endpoints

Both endpoints take no parameters and return the file's Markdown as a string inside JSON. The file is read on every request, so edits show up while `run` is running.

```bash
curl http://127.0.0.1:2323/context
```

```json
{
  "data": {
    "connector_context": "# Acme CRM\n\n## What this app is\nConnects to Acme CRM through its REST API at https://api.acme-crm.example.com/v1.\n..."
  }
}
```

```bash
curl http://127.0.0.1:2323/create_records/v1/context
```

```json
{
  "data": {
    "module_context": "# Create Records\n\n## What it does\nCreates one or more records of the chosen object...\n..."
  }
}
```

A missing file answers `404`:

```json
{
  "error": "context.md not found: create_records/v1",
  "data": { "resource": "context.md", "identifier": "create_records/v1" }
}
```

For the connector file the message is `context.md not found: connector (app-level)`.

## Connector context

Sections of the root `context.md`:

| Section                   | Required | Contents                                                                                                                         |
| ------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `## What this app is`     | Yes      | The system and the API it calls, with the base URL.                                                                              |
| `## Connection`           | Yes      | The `connection_app_type`, the exact keys read from it and what each holds.                                                      |
| `## Objects`              | Yes      | Every standard object, how the account's custom objects and custom fields are listed, and which operations each object supports. |
| `## App-wide conventions` | No       | Only what is true for every module, such as id formats or time zones.                                                            |
| `## App-wide limits`      | Yes      | Rate limits, page sizes and the error each limit produces.                                                                       |

Keep it short. Fields, examples and outputs of a module belong in the module's file.

```markdown
# Acme CRM

## What this app is
Connects to Acme CRM through its REST API at https://api.acme-crm.example.com/v1.

## Connection
A generic_api_credentials connection. `api_credentials` holds the API token, sent as
`Authorization: Bearer <token>`. A 401 means the token expired and the connection must be updated.

## Objects
Standard objects: contact, company, deal. Custom objects and custom fields are listed live from
GET /v1/schema and appear in every module's object dropdown. Deals cannot be deleted.

## App-wide limits
100 requests per minute; over it the API returns 429 with Retry-After, and the module waits and retries reads.
```

## Module context

Sections of `modules/<module>/v<N>/context.md`:

| Section                           | Required | Contents                                                                                                                                                                   |
| --------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `## What it does`                 | Yes      | The operation, the API call it makes and what it returns.                                                                                                                  |
| `## When to use it / when not to` | No       | When this module fits, and which module to use instead.                                                                                                                    |
| `## Connection`                   | Yes      | The connection the module uses and the keys it reads.                                                                                                                      |
| `## Inputs`                       | Yes      | One line per field: id, required or optional, type, allowed values or exact format, where a dropdown's options come from, and which fields appear after another is chosen. |
| `## Output`                       | Yes      | The shape of `data` and `metadata`.                                                                                                                                        |
| `## Limits & errors`              | Yes      | Hard limits, the exact error message for each, and how to avoid it.                                                                                                        |
| `## Prerequisites & order`        | No       | What must exist or happen first, such as "the company must exist before a contact is linked to it".                                                                        |
| Examples block                    | Yes      | At least one example. See below.                                                                                                                                           |

```markdown
# Create Records

## What it does
Creates one or more records of the chosen object with POST /v1/{object}s and returns the created
records as `data`, in input order, with their count in `metadata.affected_records`.

## When to use it / when not to
- Use when: a workflow creates new records.
- Don't use when: the record may already exist (use Upsert Records).

## Connection
The connector's generic_api_credentials connection; `api_credentials` holds the API token.

## Inputs
- `select_object` (required, string): the object to create. Options come from /content and list
  every standard and custom object. Choosing one reloads the form with that object's fields.
- `<object>s` (required, array): the records to create, one item per record, keyed by field id.
  `email` must be a valid address; `close_date` is YYYY-MM-DD.

## Output
`data` is `{"total", "successful", "failed", "results": [{"index", "status", "id" | "error"}]}`.

## Limits & errors
- At most 100 records per run -> "Maximum 100 records per request" -> split the input upstream.
- Unknown object -> "object not found: <name>".
```

Headings are matched without regard to case, and a trailing `##` is allowed (`## Inputs ##`).

## The examples block

Put worked examples between the exact lines `## EXAMPLES start ##` and `## EXAMPLES end ##`. Each example has a heading with the scenario, the filled-in form under `FORM DATA:`, and notes under `COMMENTS:`. At least one `FORM DATA:` is required.

````markdown
## EXAMPLES start ##

### Create one contact from the trigger

FORM DATA:
```json
{
  "summary": "Create one contact",
  "changes": [
    {
      "field_id": "select_object",
      "field_value": "contact",
      "reason": "The object to create; choosing it reloads the form with the contact fields.",
      "summary": "Object"
    },
    {
      "field_id": "contacts",
      "field_value": [{ "name": "{{ trigger_1.data.name }}", "email": "{{ trigger_1.data.email }}" }],
      "reason": "One record, keyed by the contact fields, with values from the trigger.",
      "summary": "One contact"
    }
  ]
}
```
COMMENTS:
`select_object` -> changing it reloads the records sub-form
`contacts` -> one item per record

## EXAMPLES end ##
````

* `changes` lists the fields to fill: `field_id`, the `field_value` to set, the `reason` and a short `summary`.
* Use single braces for JSON. Use double braces only for real references to another step, such as `{{ trigger_1.data.id }}`. The file is served as plain text, so don't escape them.

## Check your context

The [connector standard](/developers/getting-started-with-stacksync-cli/deploy-a-workflow-connector#the-connector-standard) checks every `context.md`:

```bash
.venv/bin/python -m stacksync_cdk.connector_checks
```

| Problem                                                                                          | Fix                                                                                     |
| ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------- |
| `context.md: the file is missing`                                                                | Add the file.                                                                           |
| `context.md: the "## Objects" section is missing` (or `is empty`)                                | Add the section with real content.                                                      |
| `context.md: still has TODO items; fill them in`                                                 | Replace every line that starts with `TODO`. Text inside `<!-- -->` comments is ignored. |
| `context.md: still has the placeholder text; write the context`                                  | Replace the template text.                                                              |
| `context.md: needs at least one example between "## EXAMPLES start ##" and "## EXAMPLES end ##"` | Add an example with `FORM DATA:`.                                                       |

The checks confirm the structure. Reviewers read the content: it must be accurate and specific to your system.

## Next steps

<Cards>
  <Card title="Deploy a workflow connector" href="/developers/getting-started-with-stacksync-cli/deploy-a-workflow-connector" />

  <Card title="Build modules" href="/developers/stacksync-cdk/modules" />
</Cards>