Hey,
I used to write slot descriptions like mini-prompts. "Extract the Jira ticket ID from the user's message. If they say 'my ticket,' look up their most recent open ticket." Paragraph-long instructions trying to get an LLM to do what a single API call could do.
That's what resolver strategies replace.
Last issue we unpacked the basics — inference policies, descriptions, validation. By the end of this one, you'll know how to wire up resolver strategies, when to use static vs dynamic resolvers, and how disambiguation keeps your plugin from guessing.
One Big Thing: Resolver Strategies
Slots collect inputs. But "my bug ticket" isn't an ID. It's context. Something has to convert that into a structured value your action can use. That's what resolver strategies do.
You can attach a resolver in two ways:
- On a custom data type (like
JiraIssue) — reusable wherever that type shows up. If you reference the same business object across plugins, this is the move. - Inline on the slot itself — tied to that one slot, not reusable. For one-off lookups or simple option lists where a whole data type isn't worth it.
There are two types: static and dynamic.
Static resolvers are usually inline — you just need a short list of options for one slot, not a reusable business object. Dynamic resolvers can go either way; if you only need the lookup in one plugin, inline keeps things simple.

Static Resolvers: The Known Menu
Static resolvers work when you know all the options upfront. Status values, categories, priority levels. A fixed list that doesn't change between users.
options:
- display_value: "Not Started"
value: 1
- display_value: "In Progress"
value: 5
- display_value: "Done"
value: 10
No API call. The user picks from the list, you get the value.

Each option has a display value (what the user sees) and a raw value (what your action receives). When you need the value in your action:
- Display value:
data.<slot_name>.display_value - Raw value:
data.<slot_name>.value
Use static resolvers for anything with a fixed set of choices — ticket statuses, expense categories, approval types. If the list changes often or depends on who's asking, you need dynamic.
Dynamic Resolvers: Live Lookup
Dynamic resolvers call an API at runtime to fetch matching records. Here's where it gets interesting — you can define multiple methods on the same data type.
Think of each method as a different way to look up the same thing:
- Get by ID: "close BUG-732" -> direct lookup
- Get by assignee: "close my tickets" -> fetch user's open tickets
- Get by project + status: "close done tickets in Project Alpha" -> filtered query
The assistant picks the right method based on what the user said.

Each method uses an HTTP action to fetch data, and you map the output to your data type. If your API nests results under a key (like response.results) — set the output mapping to point there.
Two things worth knowing:
- Method names matter. The reasoning engine uses them to decide which method fits the conversation. Keep them descriptive,
snake_case. - A resolver strategy can have one static method or multiple dynamic methods. You can't mix static and dynamic on the same strategy.
Output Cardinality: One Record vs. Many
When you configure a dynamic method, you tell it what to expect back:
Interpret output as the exact value — your action returns a single object. User said "close BUG-732," you looked it up, here's the one record.
{
"id": "BUG-732",
"title": "Set HTTP Status code correctly on custom REST API",
"priority": "high"
}
Interpret output as a list of candidate values — your action returns an array. User said "my tickets," you fetched all of them, now the assistant presents options.
[
{ "id": "BUG-732", "title": "HTTP status code fix", "priority": "high" },
{ "id": "BUG-891", "title": "Login timeout issue", "priority": "medium" },
{ "id": "BUG-445", "title": "CSS alignment bug", "priority": "low" }
]
Pick the wrong cardinality and you'll get confusing behavior. If your method always returns a list, don't tell it to expect a single object.

Disambiguation: When There's No Clear Winner
Dynamic resolvers often return multiple matches. When the assistant can't confidently pick one, it shows the candidates and lets the user choose.
User says "update my ticket." Resolver returns three open tickets. All valid. No way to guess which one.
So the assistant asks: "Which ticket?"
The user picks, the slot fills, the plugin continues. No hallucinated IDs. No guessing.

This is why I ship every custom data type with a resolver now. Under the hood, the resolver uses symbolic working memory to track both the candidate list and the selected value. The assistant can't accidentally swap IDs or fabricate new ones mid-conversation. The value comes from your system of record. Every time.
Quick Hits
- Developer Short: What is a Slot? — 60-second breakdown of slots if you need the 101 refresher before this issue.
- Developer Short: Resolver Strategies — Everything in today's One Big Thing, condensed into a video walkthrough.
- QOL Update: Notify doesn't need a published plugin anymore — You don't need to publish your conversational process as a plugin to invoke it from Notify. Build it, wire it, trigger it.
Worth Reading
- Stripe's Minions: One-Shot Coding Agents — Stripe built homegrown coding agents that merge 1,000+ PRs a week. Humans review, minions write start to finish. Very impressed with how they're shaping engineering with this. Part 2 goes deeper on the architecture.
- Harness Engineering at OpenAI — Three engineers, ~1M lines of code, zero manually written. "Humans steer. Agents execute." The AGENTS.md insight alone is worth the read.
- 100 Vulnerabilities Patched with 0 Humans — Ramp's security team used a detector-manager agent pattern to find and fix bugs that pen testing and static analysis missed. One engineer, four-hour hackathon, one week to ship.
Join the Community
Building plugins with resolvers? Come share what you're working on in the community.
Office Hours have been a cook. Join the cookout!
--Kevin
Developer Advocate @ Moveworks | Agent Studio
P.S. If you've built a resolver pattern that handles edge cases well, reply. I want to see it.