You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* feat(ramp): AI-optimize props — drop configure-time dropdowns, add optimized marker
Applies maintainer review feedback to the Ramp MCP action set. Validated
non-breaking against the ramp_sandbox eval suite (17/17 pass^2 on Sonnet 5),
with the sandbox extending this exact ramp code.
- ramp.app.mjs: removed async options() from userId, spendProgramId,
departmentId, locationId, transactionId (and the getPropOptions helper) —
AI-optimized actions discover IDs via the standalone List actions, not
configure-time dropdowns the agent never uses; the props are now plain
strings carrying an ID-format example plus the discovery action to run. [patch]
- app + 17 optimized actions: added the `// x-pd-ai: optimized` marker
(issue-virtual-card excluded — it uses dynamic props). [patch]
- list-limits / list-transactions / list-users / list-spend-programs:
corrected the compact-default field list in each description to match the
actual projection (e.g. display_name not name; added created_at,
is_shareable). [patch]
- all 15 optimized actions: removed the trailing period after the
[See the documentation](...) link so each description ends with the link. [patch]
- issue-virtual-card: version bump only — its userId/spendProgramId props lose
the dropdown via the app propDefinition change. [patch]
App package.json bumped 0.3.0 -> 0.3.1.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(ramp): bump transaction/transfer sources 0.0.3 -> 0.0.4
Dependent version bump on the three Ramp sources alongside the app
package.json bump (0.3.0 -> 0.3.1) in this PR; no behavior change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(ramp): expand create-user-invite + concretize list-locations example
Review feedback on the optimized action set:
- create-user-invite: expanded the terse description with purpose, required
params (email/name/role/department/location; manager optional), the List
Departments/Locations/Users cross-references, the Update User follow-up, and
the deferred-invite gotcha (user may not appear in List Users immediately).
- list-locations: made the example object fully concrete (id + entity_id UUIDs,
not just name) so the location ID format is explicit for downstream actions.
Description-only; versions already bumped in this PR (0.0.5 / 0.0.2).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(ramp): flatten issue-virtual-card to static props for MCP
Review: this action was the lone holdout still using reloadProps + additionalProps,
which are invisible to agents in MCP contexts — a scope gap vs the PR's AI-optimization
goal, since every sibling was already flattened.
- Replaced the reloadProps/additionalProps branching with fixed props: spendProgramId,
allowedCategories, blockedCategories un-hidden; primaryCardEnabled, reimbursementsEnabled,
isShareable, limit, interval, transactionAmountLimit declared as static optional props.
- Moved the form's conditional required-field enforcement into ConfigurationError guards
(linkToSpendProgram <-> spendProgramId must agree; a custom limit needs limit + interval).
- run() logic unchanged — same request body, same two modes; behavior-preserving.
- Joined the optimized set: added the marker + expanded the description with both modes,
cross-references (List Users / List Spend Programs), and a worked example.
- Kept linkToSpendProgram (no prop removal -> backwards-compatible). Minor bump 0.0.5 -> 0.1.0.
Not eval-covered (card-creation write on the shared Ramp demo account); validated by
syntax + behavior-preservation review.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(ramp): align invite description w/ schema, app minor bump, harden limit guard
Addresses three review comments:
- create-user-invite: description claimed department and location are required,
but both inherit optional:true from the app propDefinitions (only email, name,
and role are required). Aligned the description to the schema rather than
forcing the props required, since the API requirement isn't verifiable here and
the schema is the source of truth.
- package.json: bumped 0.3.1 -> 0.4.0 — issue-virtual-card is now a minor change
(0.1.0), so the app package bumps by the same (minor) segment.
- issue-virtual-card: the custom-limit guard only rejected undefined; an empty or
whitespace-only limit slipped through to formatUSD (-> undefined amount). Now
trims and rejects blank limits too, keeping the both-required rule.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(ramp): add UUID-format example to create-user-invite description
Review: the description named the List Departments/Locations/Users discovery
actions but didn't show the ID format. Added a concrete Ramp UUID example for
department/location/direct-manager IDs, retaining the discovery guidance.
Description-only; no version bump (already 0.0.5 in this PR).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: vetrivigneshwaran <vicky@pipedream.com>
Copy file name to clipboardExpand all lines: components/ramp/actions/create-department/create-department.mjs
+3-2Lines changed: 3 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -1,10 +1,11 @@
1
+
// x-pd-ai: optimized
1
2
importrampfrom"../../ramp.app.mjs";
2
3
3
4
exportdefault{
4
5
key: "ramp-create-department",
5
6
name: "Create Department",
6
-
description: "Create a new Ramp department (e.g. `Engineering`, `Marketing`). Use this to add an organizational unit before assigning users to it. Returns the new department's `id`, which you can pass to **Update User** to set a user's department, or use to filter **List Transactions** / **List Users**. [See the documentation](https://docs.ramp.com/developer-api/v1/api/departments#post-developer-v1-departments).",
7
-
version: "0.0.1",
7
+
description: "Create a new Ramp department (e.g. `Engineering`, `Marketing`). Use this to add an organizational unit before assigning users to it. Returns the new department's `id`, which you can pass to **Update User** to set a user's department, or use to filter **List Transactions** / **List Users**. [See the documentation](https://docs.ramp.com/developer-api/v1/api/departments#post-developer-v1-departments)",
Copy file name to clipboardExpand all lines: components/ramp/actions/create-location/create-location.mjs
+3-2Lines changed: 3 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -1,10 +1,11 @@
1
+
// x-pd-ai: optimized
1
2
importrampfrom"../../ramp.app.mjs";
2
3
3
4
exportdefault{
4
5
key: "ramp-create-location",
5
6
name: "Create Location",
6
-
description: "Create a new Ramp location (e.g. `New York HQ`). Use this to add a site before assigning users to it; the returned `id` can be passed to **Update User** or used to filter **List Transactions** / **List Users**. Associating an entity is optional — set the Entity ID only for multi-entity businesses that scope locations to a specific legal entity. [See the documentation](https://docs.ramp.com/developer-api/v1/api/locations#post-developer-v1-locations).",
7
-
version: "0.0.1",
7
+
description: "Create a new Ramp location (e.g. `New York HQ`). Use this to add a site before assigning users to it; the returned `id` can be passed to **Update User** or used to filter **List Transactions** / **List Users**. Associating an entity is optional — set the Entity ID only for multi-entity businesses that scope locations to a specific legal entity. [See the documentation](https://docs.ramp.com/developer-api/v1/api/locations#post-developer-v1-locations)",
Copy file name to clipboardExpand all lines: components/ramp/actions/create-user-invite/create-user-invite.mjs
+3-2Lines changed: 3 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -1,11 +1,12 @@
1
+
// x-pd-ai: optimized
1
2
importrampfrom"../../ramp.app.mjs";
2
3
import{v4asuuidv4}from"uuid";
3
4
4
5
exportdefault{
5
6
key: "ramp-create-user-invite",
6
7
name: "Create User Invite",
7
-
description: "Sends out an invite for a new user. [See the documentation](https://docs.ramp.com/developer-api/v1/reference/rest/users#post-developer-v1-users-deferred)",
8
-
version: "0.0.4",
8
+
description: "Invite a new person to your Ramp organization by email — use this to onboard an employee who doesn't yet have a Ramp account. Requires their email, first and last name, and `role` (e.g. `BUSINESS_USER`); department, location, and direct manager are optional. Run **List Departments** and **List Locations** to find valid department/location IDs, and **List Users** to find a direct manager's user ID — each is a Ramp UUID, e.g. `fffe6c22-698f-4dc5-b2b1-b35f86947d90`. This is a deferred operation, so the invited user may not appear in **List Users** immediately; once they do, use **Update User** to change their role, department, location, or manager. [See the documentation](https://docs.ramp.com/developer-api/v1/reference/rest/users#post-developer-v1-users-deferred)",
Copy file name to clipboardExpand all lines: components/ramp/actions/get-limit/get-limit.mjs
+3-2Lines changed: 3 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -1,10 +1,11 @@
1
+
// x-pd-ai: optimized
1
2
importrampfrom"../../ramp.app.mjs";
2
3
3
4
exportdefault{
4
5
key: "ramp-get-limit",
5
6
name: "Get Limit",
6
-
description: "Retrieve a single Ramp spend limit by ID. Run the **List Limits** action first to find a valid limit ID. Example: given a limit id from **List Limits**, returns the limit's display name, state (e.g. `ACTIVE`), balance, spend program, and spending restrictions. [See the documentation](https://docs.ramp.com/developer-api/v1/api/funds).",
7
-
version: "0.0.1",
7
+
description: "Retrieve a single Ramp spend limit by ID. Run the **List Limits** action first to find a valid limit ID. Example: given a limit id from **List Limits**, returns the limit's display name, state (e.g. `ACTIVE`), balance, spend program, and spending restrictions. [See the documentation](https://docs.ramp.com/developer-api/v1/api/funds)",
Copy file name to clipboardExpand all lines: components/ramp/actions/get-transaction/get-transaction.mjs
+3-2Lines changed: 3 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -1,10 +1,11 @@
1
+
// x-pd-ai: optimized
1
2
importrampfrom"../../ramp.app.mjs";
2
3
3
4
exportdefault{
4
5
key: "ramp-get-transaction",
5
6
name: "Get Transaction",
6
-
description: "Retrieve a single Ramp transaction by ID. Run the **List Transactions** action first to find a valid transaction ID. Example: given a transaction id from **List Transactions**, returns the full transaction — e.g. merchant `Facebook Ads`, amount `$135.00`, category `Advertising`, plus line items and accounting detail. [See the documentation](https://docs.ramp.com/developer-api/v1/api/transactions#get-developer-v1-transactions-transaction-id).",
7
-
version: "0.0.1",
7
+
description: "Retrieve a single Ramp transaction by ID. Run the **List Transactions** action first to find a valid transaction ID. Example: given a transaction id from **List Transactions**, returns the full transaction — e.g. merchant `Facebook Ads`, amount `$135.00`, category `Advertising`, plus line items and accounting detail. [See the documentation](https://docs.ramp.com/developer-api/v1/api/transactions#get-developer-v1-transactions-transaction-id)",
Copy file name to clipboardExpand all lines: components/ramp/actions/get-user/get-user.mjs
+3-2Lines changed: 3 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -1,10 +1,11 @@
1
+
// x-pd-ai: optimized
1
2
importrampfrom"../../ramp.app.mjs";
2
3
3
4
exportdefault{
4
5
key: "ramp-get-user",
5
6
name: "Get User",
6
-
description: "Retrieve a single Ramp user by ID. Run the **List Users** action first to find a valid user ID. Example: given a user id from **List Users**, returns that user's full record — name, email, role (e.g. `BUSINESS_OWNER`), department id, and location id. [See the documentation](https://docs.ramp.com/developer-api/v1/api/users#get-developer-v1-users-user-id).",
7
-
version: "0.0.1",
7
+
description: "Retrieve a single Ramp user by ID. Run the **List Users** action first to find a valid user ID. Example: given a user id from **List Users**, returns that user's full record — name, email, role (e.g. `BUSINESS_OWNER`), department id, and location id. [See the documentation](https://docs.ramp.com/developer-api/v1/api/users#get-developer-v1-users-user-id)",
description: "Creates a new virtual card for a given user. [See the documentation](https://docs.ramp.com/developer-api/v1/reference/rest/limits#post-developer-v1-limits-deferred)",
8
-
version: "0.0.5",
10
+
description: "Issue a new Ramp virtual card (spend limit) for a user. Run **List Users** to find the user ID. Works two ways: (1) **link to an existing spend program** — set **Link to Existing Spend Program** on and pass a **Spend Program ID** (run **List Spend Programs**), and the program governs the card's restrictions; or (2) **set a custom limit** — leave linking off and pass a **Total Limit per Interval** (e.g. `$500`) and an **Interval** (e.g. `MONTHLY`), optionally a per-transaction cap and allowed/blocked categories. Example: issue a $500/month card by passing the user's ID, `$500`, and `MONTHLY`. [See the documentation](https://docs.ramp.com/developer-api/v1/reference/rest/limits#post-developer-v1-limits-deferred)",
11
+
version: "0.1.0",
9
12
annotations: {
10
13
destructiveHint: false,
11
14
openWorldHint: true,
@@ -17,7 +20,7 @@ export default {
17
20
displayName: {
18
21
type: "string",
19
22
label: "Virtual Card Name",
20
-
description: "The name of the virtual card",
23
+
description: "A name for the virtual card, e.g. `Marketing SaaS`.",
21
24
},
22
25
userId: {
23
26
propDefinition: [
@@ -28,86 +31,65 @@ export default {
28
31
linkToSpendProgram: {
29
32
type: "boolean",
30
33
label: "Link to Existing Spend Program",
31
-
description: "Whether to link the card to an existing spend program",
32
-
reloadProps: true,
34
+
description: "Set to true to link this card to an existing spend program (then provide a **Spend Program ID** below). Leave off to set a custom limit instead.",
35
+
optional: true,
33
36
},
34
37
spendProgramId: {
35
38
propDefinition: [
36
39
ramp,
37
40
"spendProgramId",
38
41
],
39
-
hidden: true,
42
+
description: "The spend program to link the card to — a Ramp UUID, e.g. `e9d30f12-c73a-463b-bc5f-b200396359d2`. Run the **List Spend Programs** action to find valid IDs. Required when **Link to Existing Spend Program** is on; leave empty to set a custom limit.",
43
+
},
44
+
limit: {
45
+
type: "string",
46
+
label: "Total Limit per Interval (USD)",
47
+
description: "Total amount allowed per interval, in USD (e.g. `$500`). Required for a custom limit (when not linking to a spend program); ignored when a Spend Program ID is set.",
48
+
optional: true,
49
+
},
50
+
interval: {
51
+
type: "string",
52
+
label: "Interval",
53
+
description: "Reset interval for the custom limit (e.g. `MONTHLY`). Required for a custom limit.",
54
+
options: constants.INTERVALS,
55
+
optional: true,
56
+
},
57
+
transactionAmountLimit: {
58
+
type: "string",
59
+
label: "Maximum Spend per Transaction (USD)",
60
+
description: "Maximum amount per single transaction, in USD (e.g. `$100`). Optional; applies to a custom limit.",
61
+
optional: true,
40
62
},
41
63
allowedCategories: {
42
64
propDefinition: [
43
65
ramp,
44
66
"allowedCategories",
45
67
],
46
-
hidden: true,
47
68
},
48
69
blockedCategories: {
49
70
propDefinition: [
50
71
ramp,
51
72
"blockedCategories",
52
73
],
53
-
hidden: true,
54
74
},
55
-
},
56
-
asyncadditionalProps(props){
57
-
constnewProps={};
58
-
if(this.linkToSpendProgram===undefined){
59
-
returnnewProps;
60
-
}
61
-
if(this.linkToSpendProgram){
62
-
props.spendProgramId.hidden=false;
63
-
}elseif(this.linkToSpendProgram===false){
64
-
props.spendProgramId.hidden=true;
65
-
props.allowedCategories.hidden=false;
66
-
props.blockedCategories.hidden=false;
67
-
newProps.primaryCardEnabled={
68
-
type: "boolean",
69
-
label: "Primary Card Enabled",
70
-
description: "Dictates whether the user's physical card can be linked to this limit",
71
-
};
72
-
newProps.reimbursementsEnabled={
73
-
type: "boolean",
74
-
label: "Reimbursements Enabled",
75
-
description: "Dictates whether reimbursements can be submitted against this limit",
76
-
};
77
-
newProps.isShareable={
78
-
type: "boolean",
79
-
label: "Is Shareable",
80
-
description: "Dictates whether the spend limit is shareable among multiple users",
81
-
optional: true,
82
-
};
83
-
}
84
-
newProps.limit={
85
-
type: "string",
86
-
label: "Total Limit per Interval (USD)",
87
-
description: "Total amount limit per interval in USD",
88
-
};
89
-
newProps.interval={
90
-
type: "string",
91
-
label: "Interval",
92
-
description: "Time interval to apply limit to",
93
-
options: [
94
-
"ANNUAL",
95
-
"DAILY",
96
-
"MONTHLY",
97
-
"QUARTERLY",
98
-
"TERTIARY",
99
-
"TOTAL",
100
-
"WEEKLY",
101
-
"YEARLY",
102
-
],
103
-
};
104
-
newProps.transactionAmountLimit={
105
-
type: "string",
106
-
label: "Maximum Spend per Transaction (USD)",
107
-
description: "Max amount per transaction in USD",
75
+
primaryCardEnabled: {
76
+
type: "boolean",
77
+
label: "Primary Card Enabled",
78
+
description: "Whether the user's physical card can be linked to this limit. Applies to a custom limit.",
108
79
optional: true,
109
-
};
110
-
returnnewProps;
80
+
},
81
+
reimbursementsEnabled: {
82
+
type: "boolean",
83
+
label: "Reimbursements Enabled",
84
+
description: "Whether reimbursements can be submitted against this limit. Applies to a custom limit.",
85
+
optional: true,
86
+
},
87
+
isShareable: {
88
+
type: "boolean",
89
+
label: "Is Shareable",
90
+
description: "Whether the spend limit is shareable among multiple users.",
thrownewConfigurationError("A Spend Program ID was provided but 'Link to Existing Spend Program' is off — turn it on to link, or clear the Spend Program ID to set a custom limit.");
thrownewConfigurationError("A custom card limit needs both a Total Limit per Interval (USD) and an Interval — provide both, or link to a spend program instead.");
Copy file name to clipboardExpand all lines: components/ramp/actions/list-departments/list-departments.mjs
+3-2Lines changed: 3 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -1,10 +1,11 @@
1
+
// x-pd-ai: optimized
1
2
importrampfrom"../../ramp.app.mjs";
2
3
3
4
exportdefault{
4
5
key: "ramp-list-departments",
5
6
name: "List Departments",
6
-
description: "Retrieve a list of Ramp departments. Use this to find department IDs for other actions such as **Update User** and **List Transactions**. Example: returns `{ id, name }` pairs such as `{ \"id\": \"fffe6c22-698f-4dc5-b2b1-b35f86947d90\", \"name\": \"Engineering\" }` — pass the `id` to **Update User** to set a user's department. Returns one page of up to `pageSize` results (max 100); a `page.next` value in the response means more departments exist beyond this page. [See the documentation](https://docs.ramp.com/developer-api/v1/api/departments#get-developer-v1-departments).",
7
-
version: "0.0.1",
7
+
description: "Retrieve a list of Ramp departments. Use this to find department IDs for other actions such as **Update User** and **List Transactions**. Example: returns `{ id, name }` pairs such as `{ \"id\": \"fffe6c22-698f-4dc5-b2b1-b35f86947d90\", \"name\": \"Engineering\" }` — pass the `id` to **Update User** to set a user's department. Returns one page of up to `pageSize` results (max 100); a `page.next` value in the response means more departments exist beyond this page. [See the documentation](https://docs.ramp.com/developer-api/v1/api/departments#get-developer-v1-departments)",
Copy file name to clipboardExpand all lines: components/ramp/actions/list-limits/list-limits.mjs
+3-2Lines changed: 3 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -1,11 +1,12 @@
1
+
// x-pd-ai: optimized
1
2
importrampfrom"../../ramp.app.mjs";
2
3
importutilsfrom"../../common/utils.mjs";
3
4
4
5
exportdefault{
5
6
key: "ramp-list-limits",
6
7
name: "List Limits",
7
-
description: "Retrieve a paginated list of Ramp spend limits. Returns a compact summary of each limit by default (id, name, state, balance, spend program); use **Get Limit** for the full record, or pass `fields` to include specific extra fields. Use this to find limit IDs for **Get Limit**, **Update Limit**, and **Terminate Limit**. Returns one page of up to `pageSize` results (max 100); a `page.next` value in the response means more limits exist beyond this page. [See the documentation](https://docs.ramp.com/developer-api/v1/api/funds).",
8
-
version: "0.0.1",
8
+
description: "Retrieve a paginated list of Ramp spend limits. Returns a compact summary of each limit by default (id, display_name, state, balance, spend_program_id, created_at, is_shareable); use **Get Limit** for the full record, or pass `fields` to include specific extra fields. Use this to find limit IDs for **Get Limit**, **Update Limit**, and **Terminate Limit**. Returns one page of up to `pageSize` results (max 100); a `page.next` value in the response means more limits exist beyond this page. [See the documentation](https://docs.ramp.com/developer-api/v1/api/funds)",
Copy file name to clipboardExpand all lines: components/ramp/actions/list-locations/list-locations.mjs
+3-2Lines changed: 3 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -1,10 +1,11 @@
1
+
// x-pd-ai: optimized
1
2
importrampfrom"../../ramp.app.mjs";
2
3
3
4
exportdefault{
4
5
key: "ramp-list-locations",
5
6
name: "List Locations",
6
-
description: "Retrieve a list of Ramp locations. Use this to find location IDs for other actions such as **Update User** and **List Transactions**. Example: returns `{ id, name, entity_id }` such as `{ \"name\": \"New York HQ\" }`. Returns one page of up to `pageSize` results (max 100); a `page.next` value in the response means more locations exist beyond this page. [See the documentation](https://docs.ramp.com/developer-api/v1/api/locations#get-developer-v1-locations).",
7
-
version: "0.0.1",
7
+
description: "Retrieve a list of Ramp locations. Use this to find location IDs for other actions such as **Update User** and **List Transactions**. Example: returns objects like `{ \"id\": \"961c6f01-5719-4f4c-8fef-4096a031f32a\", \"name\": \"New York HQ\", \"entity_id\": \"c0e5f8a2-9b1d-4e3a-8f6c-2d7b4a1e9f30\" }` — pass the `id` as the location ID in downstream actions. Returns one page of up to `pageSize` results (max 100); a `page.next` value in the response means more locations exist beyond this page. [See the documentation](https://docs.ramp.com/developer-api/v1/api/locations#get-developer-v1-locations)",
0 commit comments