diff --git a/.gitignore b/.gitignore index 028d6ba..33b58d2 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ .DS_Store .env dist/ +.claude/settings.local.json diff --git a/change_log.txt b/change_log.txt index fd8151e..1a3f603 100644 --- a/change_log.txt +++ b/change_log.txt @@ -1,3 +1,12 @@ +### 1.1.0 | 2026-08-04 +- gravity-flow-abilities: Add the skill — workflow guidance for Gravity Flow abilities via the WordPress Abilities API (MCP), covering step CRUD, approval policies, reassignment, and feasibility consultation. +- gravity-forms-abilities: Add a phone pitfall row and a phone step to the form-creation workflow; an omitted phoneFormat breaks rendering on older Gravity Forms versions. +- gravity-forms-abilities: Add documentation for the notification and confirmation write abilities. +- gravity-forms-abilities: Correct the shared MCP endpoint path (/wp-json/mcp/mcp-adapter-default-server) and the meta-tool names (mcp-adapter-discover-abilities, mcp-adapter-execute-ability, mcp-adapter-get-ability-info). +- gravity-forms-abilities: Document the Gravity Forms 3.0 international phone field value shape. +- gravity-forms-abilities: Fix the entries-search escape-hatch examples to use form_ids. +- gravity-forms-abilities: Require an explicit phoneFormat on phone fields — document all three valid values plus defaultCountry/showCountryCode, and surface the format_options discovery key from system-field-types. + ### 1.0.2 | 2026-06-18 - gravity-forms-abilities: Add a warning against deprecated Ready Classes in favor of the layout grid. - gravity-forms-abilities: Add documentation for the 100-entry bulk-delete cap and the count/delete loop. diff --git a/skills/gravity-flow-abilities/SKILL.md b/skills/gravity-flow-abilities/SKILL.md new file mode 100644 index 0000000..a5def79 --- /dev/null +++ b/skills/gravity-flow-abilities/SKILL.md @@ -0,0 +1,204 @@ +--- +name: gravity-flow-abilities +description: Workflow guidance for AI agents using Gravity Flow abilities via the WordPress Abilities API (MCP). Load this skill when interacting with any gravityflow/* MCP tools — triaging the workflow inbox, approving/rejecting entries, submitting user input, diagnosing stuck workflows, admin actions (cancel/restart/send-to-step), or workflow reports and activity. Provides status vocabulary, assignee-key semantics, sequencing rules, and pitfall avoidance that tool schemas alone cannot express. +license: GPL-2.0+ +compatibility: Requires Gravity Forms as the MCP host (MCP enabled under Forms → Settings → MCP, with Gravity Flow's tools enabled in its metabox) and Gravity Flow 3.2+ contributing its abilities to that endpoint +metadata: + author: gravityforms + version: "0.1.0" +--- + +# Gravity Flow Abilities — Agent Skill + +## Ability Routing + +21 abilities. Select based on intent: + +**Orient** → `system-info` (Flow version + workflow-enabled forms with step counts and pending-entry counts — call this first), `system-step-types` (registered step types with `processable` flags) + +**Triage** → `inbox-list` (pending tasks for the authenticated user), `inbox-count` + +**Search** → `status-search` (workflow entries filtered by form, workflow status, step, assignee, date range; paged) + +**Diagnose** → `workflow-status-get` (one entry: final status, current step, live assignees with per-assignee statuses, per-step status map), `timeline-get` (entry history: who did what, when, with notes) + +**Act** → `steps-process` (approve/reject/revert an approval step, or complete a user-input step, with note and field values), `timeline-note-add` (annotate an entry's workflow timeline) + +**Unstick (admin)** → `steps-restart` (mildest), `workflow-send-to-step`, `workflow-restart`, `workflow-cancel` + +**Step configuration (read)** → `steps-list` (a form's steps, summary shape; optional `entry_id` adds per-entry statuses), `steps-get` (one step's sanitized settings) + +**Build (write)** → `system-step-type-schema` (settings schema for one type — call FIRST), `steps-create`, `steps-update` (partial merge; also toggles `is_active` to deactivate/reactivate a step — the reversible alternative to delete), `steps-delete` + +**Analyze** → `reports-get` (aggregate completion counts and durations across 7 scopes), `activity-list` (recent workflow event feed — the audit view) + +All ability names use format `gravityflow/{area}-{action}`; as MCP tools they appear hyphenated (`gravityflow-inbox-list`) on Gravity Forms' endpoint, alongside the `gravityforms-*` tools. + +**Step writes are allowlisted:** only `approval`, `user_input`, and `notification` steps can be created or modified programmatically; other types (feed add-on steps, routing, etc.) return an error naming the allowlist — configure those in the Flow admin UI. `workflow_start` / `workflow_complete` are auto-managed sentinels and can never be touched. Never attempt to create or modify workflow steps via `gravityforms/feeds-*` — Flow actively refuses generic feed tools targeting its steps and redirects you to `gravityflow/steps-*`. + +## Division of Labor: Flow vs Forms + +Gravity Flow abilities return **entry IDs and workflow state — never entry field values**. Hydrate entry data with `gravityforms/entries-get`. Both toolsets are served by Gravity Forms' single MCP endpoint, so they are always available together: + +- `gravityflow/*` — workflow: inbox, statuses, assignees, timeline, processing, admin actions, reports +- `gravityforms/*` — data: entry field values, form structure, submissions, notes + +**Etiquette rules (important):** +- Never edit workflow-relevant fields via `gravityforms/entries-update` while an entry is mid-step — assignee resolution and conditions will silently desync. The one sanctioned exception is the reassignment recipe below. +- Never touch Flow steps via `gravityforms/feeds-*`. +- Workflow entry-meta keys are a legitimate escape hatch in `gravityforms/entries-search` `field_filters` when `status-search` filters aren't enough — see [references/status-reference.md](references/status-reference.md). + +## Access Modes + +Gravity Forms is the MCP host; Flow contributes its tools to GF's endpoint. Everything is gated in **Forms → Settings → MCP**, in the **Gravity Flow** metabox below Gravity Forms' own tools: + +1. **Enable MCP** (Gravity Forms' master switch, default off) — gates the whole surface. When off, no `gravityflow/*` (or `gravityforms/*`) ability is exposed or callable. +2. **Per-tool checkboxes** (default: every tool off) — Flow's metabox splits its tools into **Read-only** and **Write** columns; a tool is exposed and callable only when its box is checked. There is no blanket "read access." + +**Read-only group** (each opt-in): `inbox-list`, `inbox-count`, `status-search`, `workflow-status-get`, `timeline-get`, `steps-list`, `steps-get`, `system-info`, `system-step-types`, `system-step-type-schema`, `reports-get`, `activity-list` + +**Write & destructive group** (each opt-in): `timeline-note-add`, `steps-process`, `steps-restart`, `workflow-send-to-step`, `workflow-restart`, `workflow-cancel`, `steps-create`, `steps-update`, `steps-delete` + +If a tool is absent from discovery or a call is permission-denied, the admin has not enabled that specific tool (or Gravity Forms' MCP is off), or your user lacks the capability. Do not attempt workarounds — tell the user to enable the exact tool in Forms → Settings → MCP (the Gravity Flow metabox), or which capability is missing. + +**Admin-screen handoff URLs** (when a change needs the Flow admin UI, give the user a direct link): step settings live at `{site}/wp-admin/admin.php?page=gf_edit_forms&view=settings&subview=gravityflow&id={form_id}&fid={step_id}` — build these from `steps-list` output when recommending manual configuration. + +### Endpoint + +Flow's tools ride Gravity Forms' MCP endpoint — there is no separate Flow endpoint. On GF's dedicated endpoint (`/wp-json/mcp/gravityforms`) each tool is listed directly (`gravityflow-steps-process`) with full JSON Schemas, alongside the `gravityforms-*` tools. In GF site-endpoint mode the same abilities appear through the site MCP server's `discover-abilities` / `execute-ability` meta-tools. Same abilities either way; only transport differs. + +## Acting User Model + +MCP authenticates as a real WordPress user (application password). Every ability acts as that user — there is no "act as user X" input. + +- **Inbox is personal.** `inbox-list` returns tasks assigned to the authenticated user (directly, via role, or via resolved fields). Different credentials = different inbox. +- **Processing as self** requires the authenticated user to be a *pending assignee* on the entry's current step — the same rule the web inbox enforces. +- **Delegated processing** (`steps-process` with `assignee_key`) acts on behalf of another pending assignee. It requires workflow-admin permission AND a `note` explaining why. The action is dual-attributed: the timeline note names both identities (`[On behalf of X (key)] …`) and the activity feed records a `delegated` event. A delegated action is never indistinguishable from the assignee acting themselves. +- **Entry visibility:** entry-scoped abilities (`workflow-status-get`, `timeline-get`, `timeline-note-add`, `steps-list` with `entry_id`) succeed only when the user holds the **`gravityflow_status_view_all`** capability, is the entry's submitter, or is a current/past assignee. An invisible entry returns the same error as a nonexistent one — do not retry or enumerate; verify existence via `status-search` or ask the user. To let someone (e.g. a manager) see *other* users' entries without making them a WordPress administrator, the answer is to grant `gravityflow_status_view_all` to their role — that exact capability, never a broader role. (The MCP surface exposes no role/capability directory, so you cannot enumerate which roles already hold it; name the capability and how to grant it.) +- **Never report absence without verifying.** `system-info`'s workflow-form list is a *summary* — a form not obviously matching the goal there is NOT proof it lacks a workflow or doesn't exist. Before telling the user "no such form/workflow/step," confirm: call `steps-list { form_id }` on the candidate form (workflow-enabled forms have steps) or `status-search`. Concluding absence from a single `system-info` read is a failure mode; the target is usually discoverable with one more read. +- **Workflow content lives in the steps, not just the form.** When a request concerns instructions, notifications, assignees, due dates, or any per-step content ("update the dates", "add instructions", "who is assigned", "which notifications go out"), enumerate the workflow with `steps-list` then `steps-get` on each step — form-level settings (title, form schedule, form notifications) are only part of the surface. Editing the form and stopping there, then claiming the request is complete, is a failure mode: the step layer (step instructions, assignee/reject notifications, step schedules and due dates) usually holds most of what the request targets. Sweep every step before reporting done. + +## Core Workflows + +### Triage and act (the primary loop) + +1. `inbox-list` → pending tasks with `entry_id`, `form_id`, `step_id`, `step_name`, `step_type`, `submitter`, `workflow_timestamp`, `due_date` +2. Hydrate details as needed: `gravityforms/entries-get { entry_id }` +3. `steps-process { entry_id, status, note }` — always include a `note`; approvals without context are poor audit trail +4. Check the response: `step_status` confirms your action; `final_status` + `current_step_id` show where the workflow went next + +Sort/prioritize by `workflow_timestamp` (when the task started waiting), not `date_created` (when the entry was submitted). + +### Diagnose and unstick ("where is entry 512 stuck?") + +1. `workflow-status-get { entry_id }` → current step, how long pending, live assignees and who hasn't acted +2. `timeline-get { entry_id }` → what already happened, in whose hands it stalled +**Where admins get step IDs:** `steps-list` requires the step-builder permission, which workflow admins often lack. The per-step map in `workflow-status-get` (`steps[] { id, name, type, status }`) is the intended step-ID source for send-to-step targets. Skipped steps show status `cancelled` there. + +**When some tools are permission-denied, fall back — do not give up.** The denial of ONE tool is never the end of diagnosis; there is almost always another route: +- `inbox-list` denied → `status-search` (find pending entries by form/step/assignee) → `workflow-status-get` on a specific entry. +- `steps-list`/`steps-get` denied (step-builder permission) → `workflow-status-get` gives the per-step map, current step, assignees, and approval policy for any visible entry; `system-step-types` gives type capabilities. +- Can't find the form by guessing IDs → `system-info` lists every workflow-enabled form with its title; match the user's description against those titles, then `steps-list`/`status-search` on the match. +Only conclude "not discoverable" after the accessible routes are exhausted, and name the exact missing permission rather than inventing a cause. Never diagnose the MCP integration as "disabled" — if a tool call fails to connect, that is a transient client issue; retry. + +3. Escalate mildest-first (all admin-gated): + - `steps-restart` — reset the current step's assignee statuses and re-send notifications. Use when the assignee missed/lost the notification. + - `workflow-send-to-step { step_id }` — jump to a specific step; the current step's pending assignees are discarded. Use to skip a broken/unnecessary step. + - `workflow-restart` — reset EVERY step status and reprocess from the top. Nuclear; requires confirmation phrase. +4. Etiquette: after any admin intervention, `timeline-note-add` explaining what was done and why. + +**Recovering entries that skipped a step (no-assignee auto-complete).** When a step shows "No assignees" in the timeline and entries sailed past it (common after an assignee user is deleted or a role empties), workflow-restart is the WRONG tool — it resets everything and, if the step still has no valid assignee, the entries skip it again. The correct recovery: (1) fix the step's assignees first (via the step settings UI, or `steps-update` if the type is allowlisted) so the step has a real assignee; (2) THEN `workflow-send-to-step` each affected entry back to that step. Identify the affected set precisely (e.g. filter by the field that gated the step) rather than sweeping every entry. This needs a human decision on WHO the new assignee should be — stop and ask for that if it is not given. + +**Cancel vs restart:** `workflow-cancel` ends the workflow (assignees purged, entry kept, `final_status: cancelled`); `workflow-restart` starts it over. Cancelling is not deleting — the entry survives and can be restarted later. + +**Confirmation echo-back:** `workflow-cancel` requires `confirmation: "CANCEL WORKFLOW {entry_id}"`; `workflow-restart` requires `confirmation: "RESTART WORKFLOW {entry_id}"`. On a mismatch the error returns the exact expected phrase — echo it back precisely. Always confirm with the human before these operations. + +**Confirmation phrases are NOT self-authorization.** The echo-back exists so a human's "yes" gates the action — it is not a formality you satisfy on your own. Never construct and send a destructive confirmation in the same breath as discovering the operation; the user must have explicitly asked for THIS specific destructive action first. If they have not, stop and state exactly what you would do and what confirmation you need. This applies to every destructive tool: `workflow-cancel`, `workflow-restart`, `steps-delete`, and `steps-process` rejections/reverts. + +**Never use writes to discover.** Do not reject, delete, cancel, or restart anything to "find out" how a step is configured or what a validation rule is — that mutates real workflows and real entries. Discovery is always read-only: `steps-list`, `steps-get`, `system-step-type-schema`, `workflow-status-get`, `status-search`. If a config read is permission-denied, report that; do not substitute a destructive probe. + +### Search + +`status-search` filters: `form_id`, `status` (workflow final status), `step_id`, `assignee_key`, date range, paging. With the `gravityflow_status_view_all` capability it spans all entries; without it, results are silently limited to the user's **own submissions** — if results look incomplete, that's why (tell the user which permission is missing rather than retrying). + +For filters `status-search` doesn't offer, use `gravityforms/entries-search` with workflow meta keys as `field_filters` — key table in [references/status-reference.md](references/status-reference.md). + +### Reassignment (sanctioned recipe) + +There is no reassign ability. For steps whose assignees resolve from an entry field (assignee field, user field, email field), reassignment is exactly two calls: + +1. `gravityforms/entries-update { "entry": { "id": 787, "3": "pat@newco.com" } }` — the entry ID goes INSIDE the entry object; set the assignee field (here field 3) to the new user/email +2. `gravityflow/steps-restart { entry_id }` — re-resolves assignees from the updated field and re-sends notifications (email assignees get a fresh token link) + +This is the ONE sanctioned exception to "don't edit workflow fields mid-step," and it only works for field-resolved assignees. For steps with fixed user/role assignees, the step configuration itself must change — not yet possible via MCP; direct the user to the step settings screen. + +### Building workflow steps + +**Build it — don't just describe it.** When asked to set up a workflow, actually create the steps; do not stop at a design and ask permission to proceed. If a detail you genuinely can't know blocks *one* setting — the exact user/role to assign, a real URL — still build the full structure with a defensible placeholder (the closest matching `role|…`, or a clearly-named stand-in) and hand off ONLY that specific detail, with the exact `steps-update` call that finalizes it. Producing a plan while creating nothing fails a build request. (This is different from a pure *feasibility* question — see below — where you answer and mutate nothing.) + +1. `system-step-type-schema { step_type, form_id }` — the settings vocabulary for the type. **Unknown settings keys are rejected on create/update (nothing saves), so never guess keys.** +2. `steps-create { form_id, step_type, step_name, assignees, destination_complete, condition, settings }` — first-class inputs cover the common cases; everything else goes in `settings`. Assignees use `type|id` keys; the internal assignee-source discriminator is handled for you. New steps append to the end of the workflow. Conditions are GF conditional-logic objects (`{actionType, logicType, rules}`) gating whether the step runs. +3. Verify with `steps-list` — check order and destinations. +4. `steps-update { step_id, ... }` — partial merge; a step's type is immutable. **When entries are in flight on the step, the update is blocked until you echo `UPDATE STEP {id} AFFECTING {n} ENTRIES`** — and changing assignee settings reroutes ALL of those entries (assignees re-resolved and re-notified automatically). If the user's request itself already specifies the change ("assign it to the finance role"), that IS the authorization — echo the count-bearing confirmation and proceed, reporting the blast radius in your summary. Only stop to confirm when the request leaves the decision open or the in-flight impact plainly exceeds what the user described. +5. **Deactivate instead of delete when the intent is "stop this step from running."** `steps-update { step_id, is_active: false }` pauses a step reversibly — its config and history are kept and it can be switched back on with `is_active: true`. A bare toggle needs no confirmation phrase. This is the safe, undoable alternative; reach for delete only when a step must be permanently removed. +6. `steps-delete { step_id, confirmation }` — **permanent, no undo.** Always needs `DELETE STEP {id} FROM FORM {form_id}`; if entries sit on the step the error escalates to a count-bearing phrase (`DELETE STEP {id} AFFECTING {n} ENTRIES`). Prefer moving in-flight entries with `workflow-send-to-step` first, or deactivating (above) rather than deleting. Deletes are blocked while other steps' destinations route to the step — update those destinations first (the error names them). + +Most validation errors name the concrete problem (unknown keys, invalid assignee, bad destination, invalid enum value) — fix exactly what it names and retry. + +**Notification recipients must be valid assignee keys — there is no `submitter` recipient.** To email the person who submitted the entry (e.g. a reject notification telling an applicant the outcome), route the notification to the submission's **email field** (`email_field|{id}`) or a literal `email|{address}` — never a bare string like `"submitter"`. Unlike settings keys, notification **recipients are not always validated on save**: an invalid recipient such as `submitter` (or a non-array recipient value) can be stored *without error* and then silently send to no one. So after configuring any step or reject/revert notification, confirm the recipient resolves to a real `type|id` / `email_field` target, and never report "the submitter will be notified" unless the recipient is a valid resolvable key. When the submitter's email isn't captured in a field, that's a genuine gap to hand back to the user — not something to paper over with a `submitter` placeholder. + +### Feasibility and design questions + +When the user is asking whether something is possible, or how they would build it — **answer first, mutate nothing.** Do not create forms, steps, or entries to "demonstrate"; unrequested writes on a consultation are a failure. Read state where it helps (system-info, steps-list), confirm capabilities from [references/feasibility.md](references/feasibility.md), **always include the relevant documentation links from that reference's verified list** (feature claims without a doc link are incomplete answers), ask the narrowing questions, and set scope expectations for large builds. + +### Analytics + +- `reports-get { scope }` — scopes and required params: `all_forms` (per-form), `form` (per-month, needs `form_id`), `form_by_step` (needs `form_id`), `step_by_assignee` (needs `step_id`), `form_by_assignee` (needs `form_id`), `all_forms_by_assignee`, `assignee_by_month` (needs `assignee_key`). Defaults to the last 6 months. Rows carry `count` and `avg_duration_secs` plus scope-specific identifiers; durations are **seconds** — convert to human units when reporting. +- `activity-list` — newest-first event feed (workflow/step/assignee lifecycle), filter by `objects`, `form_id`, `limit` (default 50, max 400). Use for "who approved what today." Delegated actions appear as assignee `delegated` events where `display_name` is the acting admin and `assignee_key` is who they acted for. +- Pattern: `reports-get` finds the aggregate problem (slowest approver), `status-search` finds the concrete backlog behind it. + +## Processing Rules (steps-process) + +Full detail in [references/processing.md](references/processing.md). The essentials: + +- **Only `approval` and `user_input` steps are processable.** Anything else (notification, webhook, feed add-on steps…) returns `operation_not_supported` — those steps complete on their own; if one is stuck, use the unstick ladder instead. +- **Valid `status` by step type:** approval → `approved` | `rejected` | `revert` (revert only if the step has reverting enabled); user_input → `complete` | `in_progress` (save progress without completing). +- **Note requirements:** approval steps can be configured to REQUIRE a note on reject/revert. On that validation error, retry the same call with a `note` — COMPOSE the note yourself from the user's stated rationale (policy reference, reason, context); if they gave none, a brief professional note stating the action and who requested it is correct. Do not stall the action to ask for note wording. Delegated calls always require a note. +- **`field_values`** (user_input steps only): keys are `input_{field_id}` / `input_{field_id}.{sub}`. Only the step's *editable fields* are writable — anything else fails closed with an error naming the editable field IDs. Approval steps do not accept field values. +- **Double-submit** → `assignee_already_processed`, no state change. Not an error to retry — the work is done. + +## Status Vocabulary (essentials) + +- **Workflow final status:** `pending` (in flight), `cancelled`, or — on completion — the FINAL step's status: `approved`, `rejected`, or `complete`. A finished workflow is NOT always `complete`; treat all three as terminal. +- **Step statuses:** `pending`, `queued` (not reached yet), `complete`, plus type-specific `approved` / `rejected` / `revert`. +- **Assignee keys:** `type|id` format — `user_id|5`, `role|editor`, `email|pat@example.com`. +- **Configured ≠ actual:** a step's configured assignees (from `steps-get`) may be field-resolved (`assignee_field`, `email_field`, …) and resolve per entry at runtime. To know who can act on an entry NOW, read `workflow-status-get`, never `steps-get`. +- **Email assignees** without a WordPress account act via signed token links in notification emails — they cannot act via MCP, and no credential will give an agent their inbox. + +Full vocabulary, per-assignee meta, and the entries-search escape hatch: [references/status-reference.md](references/status-reference.md). + +## Key Pitfalls + +| Mistake | Consequence | Prevention | +|---|---|---| +| Skipping `system-info` at session start | Wrong form IDs, missed workflow forms | Call it first — it maps the workflow landscape | +| Reading `steps-get` to decide who should act on an entry | Field-resolved assignees differ per entry | Use `workflow-status-get` for live assignees | +| `steps-process` on a notification/webhook/feed step | `operation_not_supported` | Check `step_type` first; only approval and user_input are processable | +| Expecting `final_status: complete` for every finished workflow | Finished workflows record `approved`/`rejected` too | Treat `approved`, `rejected`, `complete` as terminal; `pending` means in flight | +| Editing workflow-relevant entry fields mid-step via `gravityforms/entries-update` | Assignees/conditions silently desync | Only the two-call reassignment recipe is sanctioned | +| Wrong or missing confirmation phrase on cancel/restart | `expected_confirmation` error | Echo the exact phrase from the error, including entry ID | +| Retrying entry IDs after a not-found error | IDs can't be enumerated — invisible ≡ nonexistent | Verify via `status-search`; check permissions with the user | +| `assignee_key` without a `note` | Validation error | Delegation always requires a reason note | +| `field_values` on an approval step, or on non-editable fields | Rejected fail-closed | user_input steps only; respect the editable-field list in the error | +| Sorting inbox by `date_created` | Oldest *submission* ≠ longest-*waiting* task | Sort by `workflow_timestamp` | +| Treating `status-search`'s thin results as "no entries" | Degraded mode shows own submissions only | Report the missing view-all permission instead | +| Tool absent from discovery | Admin hasn't enabled that tool (or GF's MCP is off) | Point to Forms → Settings → MCP (Gravity Flow metabox); no workarounds | +| Building/modifying steps via `gravityforms/feeds-*` | Actively refused by Flow | Use `gravityflow/steps-create` / `steps-update` / `steps-delete` | +| Guessing settings keys on steps-create/update | Unknown keys rejected, nothing saved | Call `system-step-type-schema` first | +| Using `submitter` (or a bare string) as a notification recipient | Silently stored, emails no one — recipients aren't always validated | Route to the submission's `email_field|{id}` / `email|{address}`; verify the recipient resolves | +| Updating assignees on a step with in-flight entries without warning the user | Every in-flight entry is rerouted and re-notified | Echo the count-bearing confirmation only after the user confirms the blast radius | +| Deleting a step other steps route to | Blocked — dangling destinations | Update the referencing steps' destinations first (the error names them) | + +For "can Flow do X?" feasibility consultations: [references/feasibility.md](references/feasibility.md). +For steps-process details and error codes: [references/processing.md](references/processing.md). +For status vocabulary, meta keys, and search escape hatches: [references/status-reference.md](references/status-reference.md). diff --git a/skills/gravity-flow-abilities/references/feasibility.md b/skills/gravity-flow-abilities/references/feasibility.md new file mode 100644 index 0000000..3192741 --- /dev/null +++ b/skills/gravity-flow-abilities/references/feasibility.md @@ -0,0 +1,62 @@ +# Feasibility Facts (for "can Gravity Flow do X?" consultations) + +Customers often ask whether a workflow design is possible before building. These are verified product facts — confirm, then point at the relevant abilities or admin screens. Never invent capabilities; anything not listed here should be verified against docs.gravityflow.io before claiming it. + +## Core workflow capabilities + +- **Approval chains**: unlimited sequential approval steps; per-step assignees (users, roles, emails, field-resolved); `"all"` (unanimous) or `"any"` approval policy per step; conditions on any step (GF conditional logic on field values) enable branch-per-department/amount/type designs. +- **Approval loops / send-back**: approval steps can **revert** to a user-input step (revise-and-resubmit loops) and reject-destinations can point at any earlier step — multi-round review loops are native. +- **User input steps**: assignees edit a configured subset of fields (`editable_fields`), can save progress (`in_progress`) before completing; display-fields config controls what each step's assignees see (reviewer-privacy patterns). +- **Consent capture**: use the native Gravity Forms **Consent field** (a required GDPR checkbox with descriptive text) — not a plain checkbox. Signature capture needs the Signature add-on. +- **Two-actor patterns** (candidate submits, referent completes hidden fields): initial submission + a user_input step whose editable fields are the referent-only fields. Field-level conditional logic on steps requires the step's "field conditional logic" setting. +- **External participants without WordPress accounts**: email assignees act via signed token links from notification emails — supported for approval and user input steps. They cannot use MCP. +- **Scheduling/delays**: steps can be scheduled (delay after previous step, or date/date-field based). Expiration with destinations handles "no response by X" routing; resend settings handle reminders. +- **Notifications**: per-step assignee notifications plus approval/rejection/complete notifications, all templatable with merge tags; `{workflow_entry_link}` is the assignee's action link — REQUIRED for email assignees to act. + +## Integrations (verify the add-on is installed before promising) + +- **Payment-then-review** (e.g. paid application → manual approval): two verified patterns — payment at submission via a GF payment add-on feed, or a mid-workflow `stripe_checkout` step (Flow Stripe extension) where the assignee pays through Stripe-hosted Checkout from their workflow detail page. Payment itself always happens on Stripe's hosted page — never through MCP; agents triage/diagnose payment steps and verify outcomes (payment_status, transaction id, timeline "Processed" event). Capture/refund/cancel steps automate post-payment actions. +- **Role change / user registration on approval**: GF User Registration add-on feeds run as workflow steps — approve → the registration/role-update feed step fires. Rejection routes around it. +- **Signatures**: the GF Signature add-on's field works inside workflows; approval steps can display and collect signature fields (signature on approval requires the field on the form and step display/editable config). +- **PDF generation**: Gravity Flow PDF add-on generates PDFs from entries with merge tags (including signatures) as a workflow step. +- **Feed add-on steps**: most GF feed add-ons (webhooks, email marketing, sheets connectors…) can run as workflow steps, i.e. "after approval, push to X". +- **Form-to-form**: Form Connector add-on creates/updates entries in other forms as steps (intake → per-team forms patterns). + +## Documentation links (verified) + +Cite the SPECIFIC article for each capability you mention — a feasibility answer without deep links is incomplete. Verified URLs: + +**Gravity Flow — steps** +- Approval step: https://docs.gravityflow.io/approval-step-type/ +- User Input step: https://docs.gravityflow.io/user-input-step-type/ +- Notification step: https://docs.gravityflow.io/notification-step-type/ +- Choice Routing step: https://docs.gravityflow.io/choice-routing-step/ +- Outgoing Webhook step: https://docs.gravityflow.io/outgoing-webhook-step-type/ +- Update User step: https://docs.gravityflow.io/update-user-step/ +- Types of steps and where they come from: https://docs.gravityflow.io/types-of-steps-and-where-they-come-from/ +- Step condition: https://docs.gravityflow.io/condition/ +- Next Step / routing: https://docs.gravityflow.io/next-step/ +- Schedule / delay: https://docs.gravityflow.io/schedule/ + +**Gravity Flow — categories** (deep-link within when the topic isn't listed above) +- Flow fundamentals: https://docs.gravityflow.io/category/flow-fundamentals/ +- Extensions (PDF, Form Connector, Stripe…): https://docs.gravityflow.io/category/extensions/ +- Developer reference: https://docs.gravityflow.io/category/developers/ + +**Gravity Forms — fields & logic** +- Consent field (GDPR checkbox): https://docs.gravityforms.com/consent/ +- Signature field (needs the Signature add-on): https://docs.gravityforms.com/signature/ +- Enabling conditional logic for fields: https://docs.gravityforms.com/enable-conditional-logic/ +- Conditional logic for notifications: https://docs.gravityforms.com/enable-conditional-logic-for-notifications/ +- Conditional logic for feeds: https://docs.gravityforms.com/enabling-conditional-logic-for-feeds/ +- Merge tags: https://docs.gravityforms.com/category/user-guides/merge-tags-getting-started/ + +## Scope expectations + +For large multi-workflow asks (e.g. "eight country-specific incorporation workflows"), set expectations: design one workflow as the template, validate it end-to-end, then replicate per variant — and ask the narrowing questions first (which steps differ per country/region? who acts at each step? what does 'done' mean?). Do not attempt to build the entire estate in one pass. + +## Currently NOT possible via abilities + +- Creating WordPress pages/posts (inbox blocks, dashboards) — hand off to the human with exact instructions. +- Creating/modifying step types outside the allowlist (approval, user_input, notification) — feed-addon and routing steps are configured in the Flow admin UI. +- Acting as an email assignee (no credential exists) — only delegated processing by a workflow admin. diff --git a/skills/gravity-flow-abilities/references/processing.md b/skills/gravity-flow-abilities/references/processing.md new file mode 100644 index 0000000..6576a01 --- /dev/null +++ b/skills/gravity-flow-abilities/references/processing.md @@ -0,0 +1,70 @@ +# steps-process — Complete Guide + +`gravityflow/steps-process` performs an assignee action on an entry's **current** step. It cannot target an arbitrary step — the workflow's position decides what is processable. + +## Inputs + +| Input | Notes | +|---|---| +| `entry_id` | Required | +| `status` | Required — see per-type table below | +| `note` | Optional in general; REQUIRED when the step config demands one for the status (common on reject/revert), and ALWAYS required for delegated calls. Include one anyway — approvals without context make poor audit trail | +| `field_values` | user_input steps only; `input_{field_id}` / `input_{field_id}.{sub}` keys | +| `assignee_key` | Delegation (`type|id`); requires workflow-admin permission + `note` | + +## Valid status by step type + +| Step type | Statuses | Notes | +|---|---|---| +| `approval` | `approved`, `rejected`, `revert` | `revert` only when the step has reverting enabled — it sends the entry back to a designated user-input step without recording a rejection | +| `user_input` | `complete`, `in_progress` | `in_progress` saves `field_values` without completing the step | +| anything else | — | `operation_not_supported`. Notification/webhook/feed steps complete autonomously; if one is stuck, use `steps-restart` / `workflow-send-to-step` | + +`system-step-types` reports a `processable` flag per type — check it when unsure. + +## Authorization + +- **As self:** authenticated user must be a *pending* assignee on the current step (directly, via role, or via a field that resolved to them). Same rule as the web inbox. +- **Delegated (`assignee_key`):** requires workflow-admin permission. The key must resolve to a *pending* assignee on the current step. `note` is required. The result is dual-attributed: + - Timeline note: attributed to the acting admin, body prefixed `[On behalf of {display_name} ({key})]` + - Activity feed: a `delegated` assignee event (acting admin in `display_name`, acted-for assignee in `assignee_key`) alongside the normal status event + +## field_values and editable fields + +User-input steps declare which fields assignees may edit. `field_values` is validated fail-closed: + +- Keys must match `input_{field_id}` or `input_{field_id}.{sub}` / `input_{field_id}_{sub}` for compound fields +- Every referenced field must be in the step's editable list — otherwise the call fails with an error naming the editable field IDs, and nothing is saved +- Approval steps accept no `field_values` at all + +To know the editable fields in advance: `steps-get` on the current step. Value formats follow Gravity Forms conventions (see the gravity-forms-abilities skill's field-config reference). + +## Response shape + +```json +{ + "success": true, + "step_status": "approved", + "feedback": "Entry Approved", + "final_status": "pending", + "current_step_id": 42 +} +``` + +- `step_status` — the status you requested, confirmed +- `feedback` — human-readable pipeline message +- `final_status` + `current_step_id` — where the workflow stands NOW (the workflow may have advanced several steps: notifications/webhooks between interactive steps complete inline). `current_step_id: null` with a terminal `final_status` means the workflow finished + +After processing, trust this response over assumptions — reject destinations and conditional branches mean the "next" step is not always the next in order. + +## Errors + +| Error | Meaning | Agent response | +|---|---|---| +| `operation_not_supported` | Current step type is not processable | Use the unstick ladder (steps-restart / send-to-step), not repeated processing | +| `assignee_already_processed` | This assignee already acted on this step | Done — do not retry; check `workflow-status-get` for current state | +| `gravityflow_ability_validation_failed` | Names each concrete failure (e.g. "note: A note is required") | Retry the same call with the missing/corrected values | +| `gravityflow_ability_field_not_editable` | `field_values` touched a non-editable field; error names the editable IDs | Resend with only listed fields; report the rest to the user | +| `gravityflow_ability_not_pending_assignee` | You are not a pending assignee on the current step | Check `workflow-status-get` assignees; do not escalate on your own | +| `gravityflow_ability_delegation_denied` / `gravityflow_ability_note_required` | Delegation needs workflow-admin permission and a reason note | Add the note; if permission is missing, hand back to the user | +| Entry not found | Entry nonexistent OR not visible to this user | Indistinguishable by design — verify via `status-search`, don't enumerate | diff --git a/skills/gravity-flow-abilities/references/status-reference.md b/skills/gravity-flow-abilities/references/status-reference.md new file mode 100644 index 0000000..f1e851d --- /dev/null +++ b/skills/gravity-flow-abilities/references/status-reference.md @@ -0,0 +1,92 @@ +# Status Vocabulary, Assignee Keys, and Meta-Key Escape Hatch + +## Workflow final status (`final_status`) + +| Value | Meaning | +|---|---| +| `pending` | Workflow in flight — a current step exists | +| `cancelled` | Workflow cancelled — assignees purged, entry retained | +| `complete` | Finished; final step was a non-decision step (e.g. user input) | +| `approved` | Finished; final step was an approval that was approved | +| `rejected` | Finished; final step was an approval that was rejected | + +Key fact (verified against live behavior): on completion, Flow records the **final step's status** as the workflow status. Agents must treat `approved`, `rejected`, and `complete` all as terminal. `current_step` is `null` for any terminal status and also before the workflow starts. + +A rejected approval does not necessarily end the workflow — reject destinations can route to earlier steps or alternate branches. Read `workflow-status-get` after acting rather than assuming. + +## Step statuses + +| Value | Meaning | +|---|---| +| `queued` | Step not reached yet | +| `pending` | Step active, waiting on assignees | +| `complete` | Step finished (user input completed, notification sent, feed processed…) | +| `approved` / `rejected` | Approval step outcome | +| `revert` | Approval reverted to a user-input step for changes | +| `cancelled` | Step was skipped (workflow-send-to-step) or the workflow was cancelled while it was active | + +## Per-assignee statuses + +Within a pending step, each assignee has their own status (`pending`, `approved`, `rejected`, `complete`). Multi-assignee approval steps combine them by policy — `workflow-status-get`'s `current_step.approval_policy` states it directly: `"all"` (unanimous — every assignee must act; one approval with the step still pending is normal, name who is still pending) or `"any"` (first decision wins). The live list is `assignees[] { key, display_name, status }`. + +This policy is a **configurable step setting**, not a fixed law. If a workflow is stuck because it demands unanimous approval and the user wants any-one-approves instead (or vice versa), that is a `steps-update` on the step's approval settings — surface it as the real remedy (or a decision point to confirm), rather than only restarting/re-notifying to chase the missing approvals. + +## Assignee key format + +`type|id`: + +| Key | Resolves to | +|---|---| +| `user_id|5` | WordPress user ID 5 | +| `role|approver` | Every user with the role | +| `email|pat@example.com` | An email address (may have no WP account) | + +Step *configurations* may also use field-resolved types (`assignee_field`, `assignee_user_field`, `email_field`) that resolve per entry at runtime — which is why `steps-get` shows configured assignees but only `workflow-status-get` shows an entry's actual ones. + +**Email assignees** act through signed token links embedded in notification emails. They never authenticate to WordPress, so no MCP credential corresponds to them. An agent cannot act *as* an email assignee — only a workflow admin can act *on behalf of* one via delegated `steps-process` with `assignee_key: "email|..."`. + +**"Their link doesn't work" playbook** — always cover all three parts: (1) explain the model — email assignees act via the signed link in their notification, not by logging in, and links are entry+step+assignee-specific and can expire or be superseded; (2) verify with `workflow-status-get` that the step is still pending and they are still a listed assignee (if the step moved on, the old link is dead by design); (3) remediate with `steps-restart` (admin) to re-send a fresh token link — or delegated `steps-process` if the admin should act for them. Also check the step's notification message actually contains `{workflow_entry_link}` (use `{workflow_entry_link:page_id=N}` to point the link at a specific front-end inbox page). + +## Workflow entry meta keys (escape hatch) + +When `status-search` filters aren't expressive enough, these meta keys work as `field_filters` keys in `gravityforms/entries-search`: + +| Key | Value | +|---|---| +| `workflow_final_status` | Final status (table above) | +| `workflow_step` | Current step ID (integer) | +| `workflow_step_status_{step_id}` | That step's status for the entry | +| `workflow_user_id_{user_id}` | Per-assignee status when user {id} is/was an assignee | +| `workflow_role_{role}` | Per-assignee status for a role assignee | +| `workflow_email_{email}` | Per-assignee status for an email assignee | +| `workflow_timestamp` | Unix timestamp the current step started | + +Example — all entries stuck on step 41 in form 3: + +```json +{ + "form_ids": [3], + "search_criteria": { + "field_filters": [ + { "key": "workflow_step", "value": "41" } + ] + } +} +``` + +Note: GF's `entries-search` takes `form_ids` (an array), not `form_id`. + +Example — everything user 7 has ever approved on form 3: + +```json +{ + "form_ids": [3], + "search_criteria": { + "field_filters": [ + { "key": "workflow_user_id_7", "value": "approved" } + ] + } +} +``` + +Prefer `status-search` when its filters suffice — it applies workflow-aware shaping and permission scoping. The escape hatch is subject to GF's entry permissions, not Flow's entry-visibility predicate. diff --git a/skills/gravity-forms-abilities/SKILL.md b/skills/gravity-forms-abilities/SKILL.md index 0deeb00..49077c8 100644 --- a/skills/gravity-forms-abilities/SKILL.md +++ b/skills/gravity-forms-abilities/SKILL.md @@ -5,14 +5,14 @@ license: GPL-2.0+ compatibility: Requires a WordPress site with Gravity Forms 2.9+ and the MCP endpoint enabled (GF Settings → MCP) metadata: author: gravityforms - version: "1.0.0" + version: "1.0.3" --- # Gravity Forms Abilities — Agent Skill ## Ability Routing -25 abilities across 7 categories. Select based on intent: +32 abilities across 8 categories. Select based on intent: **Discover** → `system-field-types` (field types), `system-info` (site identity, version, license, add-ons — includes `site_url` and `site_name` for multi-site disambiguation), `forms-list` (all forms as summaries: id, title, is_active, date_created, field_count), `forms-get` (single form with full field detail) @@ -26,7 +26,9 @@ metadata: **Integrations** → `feeds-list`, `feeds-create`, `feeds-update`, `feeds-delete` -**Notifications** → `notifications-list`, `notifications-send` (re-send for existing entry) +**Notifications** → `notifications-list`, `notifications-create` / `notifications-update` / `notifications-delete` (targeted config edits — the canonical path, NOT forms-update), `notifications-send` (re-send for an existing entry) + +**Confirmations** → `confirmations-list`, `confirmations-create` / `confirmations-update` / `confirmations-delete` (the message / page / redirect a submitter sees after submitting) **Audit** → `notes-list`, `notes-add` (annotate entries) @@ -41,9 +43,9 @@ The MCP settings page (GF Settings → MCP) gates access with a master switch pl So an ability is available only when **Enable MCP is on AND that specific tool is checked**. A freshly enabled integration exposes nothing until tools are opted in. -**Read-only group** (each opt-in): `forms-get`, `forms-list`, `forms-analyze-logic`, `entries-get`, `entries-search`, `entries-count`, `submissions-validate`, `feeds-list`, `notifications-list`, `notes-list`, `system-info`, `system-field-types` +**Read-only group** (each opt-in): `forms-get`, `forms-list`, `forms-analyze-logic`, `entries-get`, `entries-search`, `entries-count`, `submissions-validate`, `feeds-list`, `notifications-list`, `confirmations-list`, `notes-list`, `system-info`, `system-field-types` -**Write & destructive group** (each opt-in): `forms-create`, `forms-update`, `forms-delete`, `forms-duplicate`, `entries-create`, `entries-update`, `entries-delete`, `feeds-create`, `feeds-update`, `feeds-delete`, `submissions-submit`, `notifications-send`, `notes-add` +**Write & destructive group** (each opt-in): `forms-create`, `forms-update`, `forms-delete`, `forms-duplicate`, `entries-create`, `entries-update`, `entries-delete`, `feeds-create`, `feeds-update`, `feeds-delete`, `submissions-submit`, `notifications-send`, `notifications-create`, `notifications-update`, `notifications-delete`, `confirmations-create`, `confirmations-update`, `confirmations-delete`, `notes-add` If an ability is not available (absent from discovery, or a direct call is permission-denied), the admin has not enabled that specific tool (or MCP itself is off). Do not attempt workarounds — tell the user to enable the exact tool, and Enable MCP, in GF Settings → MCP. @@ -51,18 +53,18 @@ If an ability is not available (absent from discovery, or a direct call is permi The MCP settings page also controls how GF abilities are exposed: -- **Site MCP** (default) — GF abilities are registered on the shared WordPress MCP endpoint (`/wp-json/mcp/v1`). They appear alongside abilities from other plugins and are accessed through the default server's meta-tools (`discover-abilities`, `execute-ability`, `get-ability-schema`). +- **Site MCP** (default) — GF abilities are registered on the shared WordPress MCP endpoint (`/wp-json/mcp/mcp-adapter-default-server`). They appear alongside abilities from other plugins and are accessed through the default server's meta-tools (`mcp-adapter-discover-abilities`, `mcp-adapter-execute-ability`, `mcp-adapter-get-ability-info`). - **Dedicated Endpoint** — GF registers its own MCP server at `/wp-json/mcp/gravityforms`. Each ability becomes a direct MCP tool (e.g., `gravityforms-forms-get` instead of going through `execute-ability`). GF abilities are hidden from the default server. **When using dedicated endpoint mode:** - Tool names use hyphen format: `gravityforms-forms-get`, `gravityforms-entries-search`, etc. (the `/` in ability names is converted to `-`) -- Each tool has its own full JSON Schema — no need to call `get-ability-schema` first +- Each tool has its own full JSON Schema — no need to call `mcp-adapter-get-ability-info` first - The MCP client must be configured to connect to the GF server endpoint separately - Both servers can coexist — the default server serves other plugins' abilities while GF serves its own **When using site MCP mode (default):** -- All abilities accessed through the shared endpoint's `execute-ability` meta-tool -- Tool name passed as a parameter: `execute-ability` with `{"ability": "gravityforms/forms-get", ...}` +- All abilities accessed through the shared endpoint's `mcp-adapter-execute-ability` meta-tool +- Tool name passed as a parameter: `mcp-adapter-execute-ability` with `{"ability": "gravityforms/forms-get", ...}` - This is the simpler setup — one MCP connection covers all plugins The agent does not need to know which mode is active — the MCP client handles routing. The same abilities are available in both modes; only the transport differs. @@ -72,12 +74,17 @@ The agent does not need to know which mode is active — the MCP client handles ### Creating a Form 1. Call `system-field-types` — discover available types and capabilities -2. Build form object with `title` and `fields` array +2. Build form object with `title` and `fields` array — for `phone` fields, ALWAYS set `phoneFormat` explicitly (see the phone section below) 3. **Include a `notifications` object** — `forms-create` does NOT auto-create a default admin notification (unlike the GF admin UI). Without one, submissions are saved but no email is sent. 4. Call `forms-create` — returns `form_id` and `edit_url` Never guess field types. `system-field-types` returns `supports_choices`, `has_inputs`, `default_inputs`, and support flags for each type. +**International phone field (Gravity Forms 3.0).** The `phone` field is still one type, but it has a `phoneFormat` setting with exactly three valid values: `"standard"` (US-masked plain string), `"international"` (unformatted plain string), or `"formatted"` (international UI, paired with a `defaultCountry` like `"us"`). The `system-field-types` phone entry reports the site's valid values as `format_options` — use those exact strings and never invent or abbreviate others; an unknown `phoneFormat` breaks form rendering. A **formatted** phone does NOT store a plain string — its value is a JSON object with the keys `country`, `national`, `formatted`, and `e164` (the `e164` value is validated against the E.164 standard). This changes how every entry-facing ability handles it: +- **Creating the field** (`forms-create` / `forms-update`): ALWAYS set `phoneFormat` explicitly — `"standard"` for a US phone, `"formatted"` (plus `defaultCountry`) for international. Do not omit it: older Gravity Forms versions do not backfill an omitted format on API-created fields, which breaks form rendering. +- **Reading** (`entries-get` / `entries-search`): a formatted phone comes back as that JSON object, not a plain number — parse it (use `e164` for the canonical number), don't treat it as a string. +- **Writing / submitting** (`entries-update`, `submissions-submit`, `submissions-validate`): supply the JSON object with a valid `e164`, not a bare number, or validation fails. (`entries-create` is a raw insert, so match the same shape to keep the value usable.) + **Default admin notification template:** ```json { @@ -106,7 +113,22 @@ Use `{admin_email}` for site admin, or a specific address. `{all_fields}` render 2. Modify the returned fields array (add/remove/change) 3. Call `forms-update` with the complete form object -`notifications` and `confirmations` merge by key — safe for partial updates. `fields` does NOT merge. +`notifications` and `confirmations` passed to `forms-update` merge by key — handy when standing up a whole form at once. For **targeted edits to a single notification or confirmation — including deletion — use the dedicated tools below**, not `forms-update` (they don't round-trip the whole form, so they can't drop fields). `fields` does NOT merge. + +### Notifications & Confirmations + +Notifications (emails) and confirmations (the message / page / redirect shown after submit) are keyed objects on the form. Edit them with the dedicated tools — the canonical path. + +**Always read before you write.** Call `notifications-list` / `confirmations-list` first to get the `id` of the item to change (the list carries the full objects; there is no separate "get one"). + +- **Create** → `notifications-create` / `confirmations-create` with a settings object; the tool generates and returns the id. + - A notification needs `name`, `event` (e.g. `form_submission`), `to` (an email, or a field id / routing per `toType`), `subject`, and `message` (merge tags + HTML OK). + - A confirmation needs `name` and a `type`: `message` (needs `message`), `page` (needs `pageId`), or `redirect` (needs `url`). +- **Update** → `notifications-update` / `confirmations-update` with the `notification_id` / `confirmation_id` and only the keys to change (partial merge; the id is immutable). The result must still satisfy the required fields above. +- **Delete** → `notifications-delete` / `confirmations-delete` by id. The form's **default confirmation cannot be deleted** (edit it instead) — every form keeps one fallback. +- **Route by condition** → add a `conditionalLogic` object (`{actionType, logicType, rules}`) so a notification sends — or a confirmation shows — only on matching submissions. For notifications `actionType: "show"` means "send when matched"; the default confirmation shows when none match. See [references/conditional-logic.md](references/conditional-logic.md). + +Common shapes: route different emails to clinicians vs patients (two notifications, each with `conditionalLogic` on a role/type field); show a tailored thank-you page per department (conditional confirmations + the default as fallback). ### Submitting a Form @@ -328,6 +350,7 @@ For CL structure details, operators, and common patterns, see [references/condit | Fileupload field without `allowedExtensions`/`maxFileSize` | Accepts any file type/size — security risk | Always set `allowedExtensions` and `maxFileSize` — see field-config reference | | Creating a form without `notifications` | Submissions saved but no email sent — admin never notified | Always include a notification object — see "Creating a Form" workflow | | Creating a name field without `nameFormat: "advanced"` | First/Last sub-inputs render stacked vertically instead of side-by-side | Always set `"nameFormat": "advanced"` and `"size": "large"` on name fields — see field-config reference | +| Creating a phone field without an explicit `phoneFormat` (or with an invented value) | On older GF versions the field fatals when rendered (form editor and frontend); format behavior is undefined | ALWAYS set `phoneFormat` explicitly to one of the values `system-field-types` reports in `format_options` (`"standard"`, `"international"`, `"formatted"`) — see field-config reference | | Passing multiselect values as comma-separated string | Data loss when values contain commas (e.g., "Atlanta, GA") | Always pass multiselect values as an **array**: `"input_1": ["Red", "Blue"]` — see field-config reference | | User asks to "create a form and add it to a page" | Cannot create WordPress pages/posts — only GF abilities exist | Create the form, then tell the user the shortcode `[gravityform id="X" title="true"]` to embed manually. Page/post creation is not currently available via the Abilities API. | | Ability not found (e.g., `forms-create`) | Site admin has not checked that specific tool (or Enable MCP is off) in MCP settings | Tell the user to enable the exact tool — and Enable MCP — in GF Settings → MCP. There is no blanket "write access" toggle; each tool is opted in individually. Do not attempt workarounds. | diff --git a/skills/gravity-forms-abilities/references/conditional-logic.md b/skills/gravity-forms-abilities/references/conditional-logic.md index 1229c1d..6532a61 100644 --- a/skills/gravity-forms-abilities/references/conditional-logic.md +++ b/skills/gravity-forms-abilities/references/conditional-logic.md @@ -176,7 +176,7 @@ CL is set as a property on individual fields during `forms-update`: ### Send notification only for specific selections -Set on the notification object (via `forms-update` on the `notifications` property): +Set the `conditionalLogic` on the notification via `notifications-update` (the canonical targeted path; `notifications-create` accepts it too): ```json { diff --git a/skills/gravity-forms-abilities/references/field-config.md b/skills/gravity-forms-abilities/references/field-config.md index d826886..069c6d9 100644 --- a/skills/gravity-forms-abilities/references/field-config.md +++ b/skills/gravity-forms-abilities/references/field-config.md @@ -203,7 +203,16 @@ Example — multi-file with limit: | Property | Type | Description | |---|---|---| -| `phoneFormat` | string | `"standard"` (US: (###) ###-####) or `"international"` (free-form) | +| `phoneFormat` | string | **Always set explicitly.** Exactly one of: `"standard"` (US: (###) ###-####), `"international"` (plain unformatted input), or `"formatted"` (international UI with country selector; stores JSON — see SKILL.md). Never invent other values — an unknown format breaks form rendering. `system-field-types` reports the site's valid values in `format_options` (sites can add custom formats via filter). | +| `defaultCountry` | string | `"formatted"` only. Two-letter lowercase country code preselected in the country dropdown (e.g. `"us"`, `"gb"`). | +| `showCountryCode` | boolean | `"formatted"` only. Whether the country calling code is shown in the input. Defaults to `true`. | + +```json +{ "type": "phone", "label": "Phone", "phoneFormat": "standard" } +``` +```json +{ "type": "phone", "label": "Mobile", "phoneFormat": "formatted", "defaultCountry": "us" } +``` ### Consent (`type: consent`)