# Add Actions Skill

Add all actions for a resource to one partial file, then drive it through `stackone validate` and the build gates.

## Rules

- Add ALL actions for a resource in one partial — no one-by-one
- Map EVERY parameter from research data (required + optional)
- Skip deprecated endpoints only
- Gates decide completion — a resource is done when the gates exit 0, not when it looks done
- Don't proceed to next resource until current passes

## Workflow

### Step 1: Read Research Data

```bash
Read .connector-dev/{{provider}}/research/endpoints/resources/{{resource}}.yaml
Read .connector-dev/{{provider}}/research/auth/auth_config.yaml
```

Extract: all endpoints, every parameter (path/query/body), nested objects, enums, scopes.

### Step 2: Build the Partial File

> **Write each resource partial complete, in one `Write`.** All its actions, all their
> inputs, all their args — then run the gate. Do not create a partial and grow it action by
> action, and do not patch one gate finding per `Edit`.
>
> Measured across real runs, this is a 6× spread: one produced 23 actions in 12 file
> operations, another took 23 operations to produce 7. Every extra operation is a turn, and
> turns are the budget that decides whether validate is reached at all.

> **`actionId` mirrors the provider's own naming — exactly.** If the provider calls the
> operation "people search", the action is `people_search`. If it calls it
> `conversations.list`, the action is `conversations_list`. Take the provider's operation
> name, lowercase it, and replace separators with underscores. Nothing else.
>
> Do **not** reorder it into a verb-first house style. `people_search` stays `people_search`;
> it does not become `search_people`. A connector that renames the provider's operations
> forces every caller to learn a second vocabulary for the same API, and it is the single
> largest source of scored naming deviations.
>
> This is why the endpoint `id` recorded in research matters: build creates one action per
> `endpoints[].id`, and gate B3 requires the actionId to match it exactly. Get the name right
> in research and the build inherits it.

Resolve `$CONNECTOR_PATH` from state first (see `docs/PATHS.md §Connector-path resolution`). Create `$CONNECTOR_PATH/{{provider}}.{{resource}}.s1.partial.yaml` with all actions ordered by dependency:

> **Filenames: lowercase letters, digits and dots only — never a hyphen, underscore, space,
> comma or capital.** A multi-word provider runs together as one token:
> `azureblobstorage`, never `azure-blob-storage` or `azure_blob_storage`. The filename is
> parsed — a partial's resource is read out of it and must match a `$ref` — so a hyphen
> produces a resource nothing refers to and fails wiring later without naming the filename
> as the cause.


```
LIST → GET → CREATE → UPDATE → DELETE
```

**For each action, use these skills for correct configuration:**

| What | Skill |
|------|-------|
| File structure and naming conventions | `connector-patterns` (`connector-patterns/references/naming-conventions.md`) |
| Action structure (unified vs non-unified) | `skills/build-connector/references/action-config.md` |
| Input definitions (types, required, in, properties) | `skills/build-connector/references/input-config.md` |
| Args mapping (value, in, condition, spread, arrayFormat) | `skills/build-connector/references/args-config.md` |
| REST HTTP step functions | `skills/build-connector/references/step-function-request.md` |
| Multipart upload or binary download | `skills/build-connector/references/step-function-upload-download.md` |
| Auth requirements / scopes | `skills/build-connector/references/action-config.md` (authRequirements section) |

**Parameter mapping — research data to action config:**

| Research location | Input `in` | Args `in` | Notes |
|---|---|---|---|
| `path_params` | `path` | Interpolated in URL as `${inputs.name}` | Always required, no arg needed |
| `query_params` | `query` | `query` | Arrays need `arrayFormat` |
| `payload` (body fields) | `body` | `body` | Nested objects need `properties` |

**Key rules (details in `input-config` and `args-config.md`):**
- Optional args MUST have `condition: '{{present(inputs.name)}}'`
- Required args do NOT get a condition
- Arrays: use element type + `array: true` (never `type: array`)
- Nested objects: `type: object` with `properties` listing all sub-fields
- Multi-shape fields: use `variants` when a field accepts multiple distinct types (see `input-config.md`)
- Query arrays: add `arrayFormat: comma|repeat|brackets`

**authRequirements — when and how to add:**

Determine from connector state and research data:

| Condition | Action |
|-----------|--------|
| Single auth type + no `scopeDefinitions` | Do NOT add `authRequirements` |
| Multi-auth + no `scopeDefinitions` + all actions work with all auth types | Do NOT add `authRequirements` |
| `scopeDefinitions` exist | Add `authRequirements` per action from research scopes data |
| Multi-auth + some actions restricted | Add `authRequirements` per action — map auth types from research |

When adding `authRequirements`, derive per-auth-type scopes from:
1. `.connector-dev/{{provider}}/research/auth/scopes.yaml` — scope registry
2. `.connector-dev/{{provider}}/research/endpoints/resources/{{resource}}.yaml` — per-endpoint scope requirements
3. Connector's `scopeDefinitions` — which scopes are registered

Place `authRequirements` immediately after `actionId` in the partial. See `action-config.md` for full reference and patterns.

**Do NOT use `requiredScopes`** — it is blocked and will fail schema review.

**effects — always add:**

Every action MUST have `effects`. Derive by analyzing the whole action:
1. Check HTTP method (`GET` → read, `DELETE` → delete)
2. Check URL path semantics (`/search` → search, `/approve` → execute, `/archive` → delete)
3. Cross-check with action description
4. URL path semantics override HTTP method when they conflict (e.g. `POST /contacts/search` → `search`)

| Effect | When |
|--------|------|
| `read` | GET requests, list/get/download actions |
| `write` | POST/PUT/PATCH that create or modify data |
| `delete` | DELETE requests, archive/void/remove actions |
| `search` | Search/find/query endpoints (even if POST method) |
| `execute` | Non-CRUD: approve, decline, cancel, send, sync, publish |

Place after `authRequirements` (if present), before `categories`. See `action-config.md` for full derivation guide.

**For existing connectors:** If any action is missing `effects`, the `build-actions.md` auto-adds them during Phase 2 by analyzing the action's step function (method + URL) and description. No user prompt needed.

### Step 3: Add $ref to Connector YAML

Append to `$CONNECTOR_PATH/{{provider}}.connector.s1.yaml`:

```yaml
actions:
  $ref: "{{provider}}.{{resource}}"
```

Don't replace existing `$ref` entries.

### Step 4: Validate YAML

```bash
# Resolve $CONNECTOR_PATH from state (see docs/PATHS.md §Connector-path resolution)
CONNECTOR_PATH=$(yq -r '.build.connector_path // ""' ".connector-dev/{{provider}}/build-state.yaml" 2>/dev/null)
[ -z "$CONNECTOR_PATH" ] && CONNECTOR_PATH=$([ -d "src/configs" ] && echo "src/configs/{{provider}}/" || echo "{{provider}}/")

stackone validate "$CONNECTOR_PATH"
```

Fix syntax errors before proceeding.

### Step 5: Run the Build Gates

```bash
node ${CLAUDE_PLUGIN_ROOT}/scripts/gates/build.js \
  --provider {{provider}} --connector-path "$CONNECTOR_PATH" --cli-ok <true|false> --scope {{resource}}

node ${CLAUDE_PLUGIN_ROOT}/scripts/gates/conventions.js \
  --provider {{provider}} --connector-path "$CONNECTOR_PATH"
```

`--cli-ok` carries the `stackone validate` verdict from Step 4 — B1 fails when it is omitted, because an unrun check must never read as a passing one.

### Step 6: Handle the Gate Report

- **Exit 0** → proceed to next resource
- **Exit 1** → fix what the gate reported in the partial, re-run the gate. Don't move on until it passes.

When every resource is green, the connector is **built, not done**: hand off to Phase 3
(`/connector:validate {{provider}}` / the `validate-config` skill) so every action is
re-derived from the provider's live docs. Build gates compare against research; only the
validate gate catches what research itself got wrong.

## Resource Processing Order

```
Independent resources (no cross-resource ID deps) → parallel
Dependent resources (need IDs from others)         → sequential after dependency

Example:
  Batch 1 (parallel): users, contacts, departments
  Batch 2: projects (needs department_id)
  Batch 3: tasks (needs project_id)
```

## Context Compacting

**Preserve:** current resource, workflow step (1-6), completed resources, unresolved gate failures.

**Resume from:**
```bash
# $CONNECTOR_PATH from build-state.yaml (see docs/PATHS.md)
ls "$CONNECTOR_PATH"/*.partial.yaml
ls .connector-dev/{{provider}}/research/endpoints/resources/
```

---

**Remember**: All actions per resource in one partial. The gates decide completion; the main session owns resource orchestration.
