Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b6f4c25
refactor(promptforge): de-pad the pull-followups NEXT STEPS table
ArtyETH06 Aug 17, 2026
439a85a
feat(core): reject country-level locations on every geo-accepting tool
ArtyETH06 Aug 17, 2026
a336973
feat(mcp): stop telling the agent a country is a valid location filter
ArtyETH06 Aug 17, 2026
c834a15
fix(mcp): the sweep missed two prompts the issue named
ArtyETH06 Aug 17, 2026
0c3b57c
fix(mcp): close the set_filter bypass and the prompt fall-through
ArtyETH06 Aug 17, 2026
f64a208
fix(mcp): an unsupported foreign country is not an unfiltered search
ArtyETH06 Aug 17, 2026
d04045d
fix(mcp): stop asserting a country is foreign when the backend is unk…
ArtyETH06 Aug 17, 2026
f4f8df0
fix(mcp): judge a scope phrase by the country it names
ArtyETH06 Aug 17, 2026
ba86bdc
fix(mcp): the prompt gates must not answer a foreign ask with home data
ArtyETH06 Aug 17, 2026
ad82b52
fix(mcp): an exclusion is not an inclusion, and a tour is not a Monit…
ArtyETH06 Aug 17, 2026
34bb511
fix(mcp): an exclusion of the home country empties it, it does not wi…
ArtyETH06 Aug 18, 2026
63013c5
fix(mcp): a country-wide tour is a question, not a nationwide itinerary
ArtyETH06 Aug 18, 2026
9e00881
fix(mcp): keep the city when dropping the country, and see "the whole…
ArtyETH06 Aug 18, 2026
624d2f4
fix(mcp): "EU-wide" is a scope too, and two kinds need one recovery
ArtyETH06 Aug 18, 2026
0da0277
fix(mcp): a country-wide scope is answered by writing nothing
ArtyETH06 Aug 18, 2026
22744ad
fix(mcp): the country is redundant, the rest of the request is not
ArtyETH06 Aug 18, 2026
f811092
fix(mcp): never write the inverse of an exclusion, never guess the ba…
ArtyETH06 Aug 18, 2026
9dfad97
fix(mcp): scope is a property of the request, not of one argument
ArtyETH06 Aug 18, 2026
b0baac2
fix(mcp): a breadcrumb is not a filter value
ArtyETH06 Aug 18, 2026
a552e42
fix(mcp): a blocked exclusion fails the whole write closed, in one in…
ArtyETH06 Aug 19, 2026
711a940
fix(mcp): a foreign country is not "nationwide", and a named id is no…
ArtyETH06 Aug 19, 2026
0cb5767
fix(mcp): the country is read, never inferred — and never remembered
ArtyETH06 Aug 19, 2026
5eeb755
test(mcp): let the judge see the region, so a read fact beats an echo
ArtyETH06 Aug 19, 2026
1a19b8d
test(mcp): record the follow-ups scenario flake, measured not guessed
ArtyETH06 Aug 19, 2026
91a3f92
docs(mcp): the changelog described a recovery the PR now forbids
ArtyETH06 Aug 19, 2026
832bd47
perf(mcp): give pull_followups back its headroom under the 17k cap
ArtyETH06 Aug 20, 2026
b111a52
fix(mcp): the country guard's recovery pointed at the wrong things
ArtyETH06 Aug 20, 2026
2c78f92
fix(mcp): the country was the request, not a bad value in it
ArtyETH06 Aug 20, 2026
168096a
fix(mcp): where two of the last round's fixes met, they contradicted
ArtyETH06 Aug 20, 2026
0cc497f
fix(mcp): the shared recovery was wrong for four tools that are not p…
ArtyETH06 Aug 20, 2026
a7ff3d1
fix(mcp): the recovery only fires if the agent sends the country
ArtyETH06 Aug 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,38 @@ Call `leadbay_pull_followups` (NOT `leadbay_pull_leads` — those are different

For geo filters specifically: prefer the `city` shortcut on `leadbay_pull_followups({city: "Berlin"})` — the composite resolves the free-text city via `/geo/search`, returns ambiguities to disambiguate when needed (status: "ambiguous_locations" → pick an id → re-call with `city_id`), then merges the resolved admin_area into the Monitor filter as `location_ids`. If the user has already given you a numeric id, pass it as `city_id`. Don't guess admin_area ids — let the resolver do it.

**TRAVEL / IN-PERSON ROUTING** — when the user's intent is geographic and visual ("I'm going to NYC next week", "leads I should visit in person", "this week's trip", "show me followups in <city>", "plan my itinerary", "trip itinerary", "show on a map", "leads in Texas / California / France", or any phrasing that asks for a map / geographic / trip-planning view — INCLUDING state-, country-, and region-level place names):
**One workspace = one country — a country name is NEVER a location filter.** The admin-area index holds no country nodes, so `"France"` matches the *commune of Francs* and `"United States"` matches *Statesboro*: the call is silently fenced to one village and every conclusion from it is wrong. City AND country named? Keep the city, drop the country.

**On `code: "COUNTRY_LEVEL_LOCATION"` read `country_locations[].axis` and `[].kind` — the recovery differs per case and they are NOT interchangeable, and do NOT retry with another spelling or a nearby city.**

`axis: "include"`:

- `home_country`, or "nationwide" / "everywhere" → drop that ONE value. Omit the geo argument (`city` / `locations` / `location_ids`) only if nothing else was on it — then the result covers the whole workspace. If other values remain, keep them and describe the result as those places.
- `foreign_country` ("leads in France" on a US workspace) → **unsupported, not unfiltered.** Do NOT re-run without the argument: whole-workspace results are US leads and answer nothing about France. Say the workspace holds only its own country's companies.
- `supranational` ("EU", "EMEA") → name what the workspace covers, then offer the whole-workspace view as an explicit choice rather than assuming it.
- `country_indeterminate` (custom/staging backend) → its country is unknown, so claim nothing about what it holds.

`axis: "exclude"` reverses all of that — **never "omit the argument"**, which returns the very companies the user asked to remove. Excluding this workspace's own country would empty it; excluding any other country is a harmless no-op. Either way drop the value and ask what to carve out instead.

On a lens-WRITING tool (`new_lens`, `adjust_audience`, `update_lens_filter`) write NOTHING, with no re-call in any form: when the country was the only scope, and for ANY non-`foreign_country` `exclude` hit however much else came with it — dropping it and writing the rest inverts the ask.

**Never infer WHICH country this workspace serves from the user's wording** — "the whole US" does not make it one. Read `_meta.region` on any tool result — it outranks any recalled memory; on `custom`, claim nothing.

Place names never go in `keywords`, `sectors` or `refine_prompt` — text matches, not geo filters.


⚠ **On this prompt, omitting the geo argument is only HALF of a whole-workspace read.**
`leadbay_pull_followups` defaults `filtered` to true, so dropping the country still reads
the Monitor view through whatever filter a previous session persisted — an old city
filter comes back as a small, plausible cohort and you would report it as everything.
When the ask covers the whole workspace and nothing else was requested, pass
`filtered:false`. When other criteria WERE requested (a sector, a recency window, a real
city), re-send those in `set_filter` instead — that overwrites the stored filter, so
`filtered:false` would throw away the very scope I asked for. Either way, read
`active_filters` off the response and describe the scope from THAT, not from what you
intended to send.

**TRAVEL / IN-PERSON ROUTING** — when the user's intent is geographic and visual ("I'm going to NYC next week", "leads I should visit in person", "this week's trip", "show me followups in <city>", "plan my itinerary", "trip itinerary", "show on a map", "leads in Texas / California", or any phrasing that asks for a map / geographic / trip-planning view — INCLUDING state- and region-level place names, but NEVER a country):

1. Call **`leadbay_followups_map`** (same params as `pull_followups`: `city` / `city_id` / `set_filter`). Same response shape — just the explicit entry-point so the agent and the host know to route geographically.
2. Output a **per-lead place-card block** for each top follow-up, in this exact format — modern chat hosts (Claude / cowork) detect addresses + company names and surface them as a beautiful Google-Place-card carousel with our notes as the "Notes from Claude" section. Lean INTO that surface; don't fight it.
Expand Down Expand Up @@ -84,16 +115,16 @@ Markdown table with FOUR columns, sorted by `last_monitor_action_at` desc. **NO

**Active-filters line** ABOVE the table, ` · `-separated chips from `active_filters.criteria`:

| Criterion type | Chip |
|-----------------------|----------------------------|
| `location_ids` | 📍 \<resolved name\> |
| `sector_ids` | 🏷 \<sector name\> |
| `keywords` | 🔍 \<keyword\> |
| `size` | 👥 \<min\>–\<max\> |
| `last_action_date` | 📅 \<window\> |
| `last_action` | 🎯 \<action types\> |
| `liked` / `yc` | ⭐ liked / 🏅 YC |
| `custom_field*` | ⚙ \<field name\> |
| Criterion type | Chip |
| --- | --- |
| `location_ids` | 📍 \<resolved name\> |
| `sector_ids` | 🏷 \<sector name\> |
| `keywords` | 🔍 \<keyword\> |
| `size` | 👥 \<min\>–\<max\> |
| `last_action_date` | 📅 \<window\> |
| `last_action` | 🎯 \<action types\> |
| `liked` / `yc` | ⭐ liked / 🏅 YC |
| `custom_field*` | ⚙ \<field name\> |

Render `*No filters applied.*` when empty.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: "Use whenever the user names a city they'll be in and asks who to s
---


Plan a field sales tour for me in **<City or region the user is visiting (e.g. 'Limoges', 'Bay Area'). Used as the geo filter for both Monitor and Discover lookups. If not provided in the user's most recent message, ask once before proceeding.>**<if the user supplied this argument, render the short parenthetical or inline clause derived from it; otherwise empty. Source: When the visit is (e.g. 'May 24', 'next Thursday'). Surfaced in the outreach drafts as 'I'll be in <city> on <date>'.>.
Plan a field sales tour for me in **<City or region the user is visiting (e.g. 'Limoges', 'Bay Area'). Used as the geo filter for both Monitor and Discover lookups. A country is not a city: this workspace already covers exactly one country, and a country name here silently fences the tour to a same-named village. Do NOT omit the argument to recover — a city-less tour returns arbitrary leads from across the whole workspace, which is not an itinerary. Ask which city or region the visit is to. If not provided in the user's most recent message, ask once before proceeding.>**<if the user supplied this argument, render the short parenthetical or inline clause derived from it; otherwise empty. Source: When the visit is (e.g. 'May 24', 'next Thursday'). Surfaced in the outreach drafts as 'I'll be in <city> on <date>'.>.

GATE — DEFER TO TOOL RENDERING. When you call a Leadbay composite that ships its own RENDERING block (every composite in 0.9.0+ does), render the response using that block's recipe verbatim — score bars, glyph palette, column order, hide-list, link priorities, all of it. Do NOT substitute prose, a numbered list, or a different column structure even when an orchestrating prompt's body suggests alternate framing. Prompt-specific commentary (motivational nudges, summaries, next-action recommendations) belongs ABOVE or BELOW the canonical table, never in place of it.

Expand All @@ -28,7 +28,29 @@ Map my answers to the `leadbay_tour_plan` call:

# PHASE 2 — BUILD THE ITINERARY

Call `leadbay_tour_plan({city: "<the city (as extracted above)>", …scope from PHASE 1})`. If the response is `status: "ambiguous_locations"`, surface the candidates and ask me to pick one, then re-call with `city_id`.
**One workspace = one country — a country name is NEVER a location filter.** The admin-area index holds no country nodes, so `"France"` matches the *commune of Francs* and `"United States"` matches *Statesboro*: the call is silently fenced to one village and every conclusion from it is wrong. City AND country named? Keep the city, drop the country.

**On `code: "COUNTRY_LEVEL_LOCATION"` read `country_locations[].axis` and `[].kind` — the recovery differs per case and they are NOT interchangeable, and do NOT retry with another spelling or a nearby city.**

`axis: "include"`:

- `home_country`, or "nationwide" / "everywhere" → drop that ONE value. Omit the geo argument (`city` / `locations` / `location_ids`) only if nothing else was on it — then the result covers the whole workspace. If other values remain, keep them and describe the result as those places.
- `foreign_country` ("leads in France" on a US workspace) → **unsupported, not unfiltered.** Do NOT re-run without the argument: whole-workspace results are US leads and answer nothing about France. Say the workspace holds only its own country's companies.
- `supranational` ("EU", "EMEA") → name what the workspace covers, then offer the whole-workspace view as an explicit choice rather than assuming it.
- `country_indeterminate` (custom/staging backend) → its country is unknown, so claim nothing about what it holds.

`axis: "exclude"` reverses all of that — **never "omit the argument"**, which returns the very companies the user asked to remove. Excluding this workspace's own country would empty it; excluding any other country is a harmless no-op. Either way drop the value and ask what to carve out instead.

On a lens-WRITING tool (`new_lens`, `adjust_audience`, `update_lens_filter`) write NOTHING, with no re-call in any form: when the country was the only scope, and for ANY non-`foreign_country` `exclude` hit however much else came with it — dropping it and writing the rest inverts the ask.

**Never infer WHICH country this workspace serves from the user's wording** — "the whole US" does not make it one. Read `_meta.region` on any tool result — it outranks any recalled memory; on `custom`, claim nothing.

Place names never go in `keywords`, `sectors` or `refine_prompt` — text matches, not geo filters.


**Gate before calling.** If `<the city (as extracted above)>` is a country name or a supra-national scope rather than a city, do NOT call `leadbay_tour_plan` with it — a tour of an entire country is not an itinerary, and the value would resolve to a same-named village. Tell me the workspace already covers one country and ask which city or region I'm actually visiting. Otherwise:

Call `leadbay_tour_plan({city: "<the city (as extracted above)>", …scope from PHASE 1})`. If the response is `status: "ambiguous_locations"`, surface the candidates and ask me to pick one, then re-call with `city_id`. If it is `status: "country_level_location"`, do NOT retry with a spelling variant and do NOT re-call without `city` — a tour with no city is arbitrary nationwide leads, not an itinerary. Ask me which city or region I am visiting.

Split the returned `monitor_leads` into two buckets client-side using their engagement-history fields:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,76 @@ description: "Refine the kind of leads Leadbay surfaces beyond firmographics, wi

Refine the Leadbay audience prompt to: <The refinement (e.g. 'focus on hospitals running their own IT'). Set to plain English. If not provided in the user's most recent message, ask once before proceeding.>

# PHASE 1 — REFINE
Call `leadbay_refine_prompt` with `prompt=<the instruction above>`.
# PHASE 0 — GATE: RESOLVE THE REGION, STRIP THE COUNTRY, THEN CLASSIFY (may end the run)
A refine prompt shapes the KIND of company, never WHERE it is. Before any tool call:

**Step 1 — if a COUNTRY is named at all, find out which country this workspace serves,
and do it FIRST.** Every later step turns on whether the country I named is this
workspace's own, and you cannot tell that from my message: "French hospitals across
France" is a redundant clause on an FR backend and an unsupported ask on a US one, and
the language I write in says nothing about it. Do NOT guess from the country I named,
from my language, or from the fact that the request sounds plausible — strip first and
you will have already decided, silently and possibly wrongly, that the country was
redundant. Every Leadbay tool result carries the fact at `_meta.region`
(`us` | `fr` | `custom`); if no call this session has returned one, call
`leadbay_account_status` — read-only, writes nothing — and read `_meta.region` from it.
`custom` means the backend's country is unknown: claim nothing about which country it
holds. Only a place BELOW country level ("in Paris", "Texas") skips this step.

**Step 2 — now strip, and do not stop.** With the region known, if my instruction names
this workspace's own country or a whole-country scope ("nationwide", "the whole US",
"partout en France"), remove that phrase and KEEP THE REST. It is redundant, never a
filter — but it is almost never the whole instruction. "Hospitals running their own IT
nationwide" is a refinement about hospitals; "hospitals in Paris, France" is Paris plus
hospitals. Losing the rest because a country rode along is the worse error of the two.
A country that is NOT this workspace's own is not stripped — it is the whole answer, and
Step 3 handles it.

**Step 3 — classify what REMAINS**, and act on every part of it:

- **Nothing remains** (the country was the entire instruction) → **STOP HERE. Call
NOTHING.** Do not continue to PHASE 1: `leadbay_refine_prompt` would overwrite my
qualitative audience prompt and kick off an intelligence recompute to express a scope
this workspace already has. Tell me there is nothing to set because the workspace
already covers exactly that, offer the axes that do narrow an audience (sector, size,
or a sub-country region / state / county / city), and end your turn.
- **A DIFFERENT country** ("partout en France" on a US workspace) → **STOP HERE too, but
do not say "there is nothing to set" — that is false.** The ask is UNSUPPORTED, not
already-satisfied: this workspace holds only its own country's companies, so there are
no leads there to scope to. Say so plainly, do not offer an unfiltered view as if it
answered the request, and end your turn. If a qualitative part rode along with it, say
it cannot be applied to a country that is not here either.
- **A supra-national scope** ("EU-wide", "EMEA") → stop as well: name what the workspace
covers and ask whether I want that instead, rather than assuming it.
- **A sub-country place** ("prospects in Texas", "restrict to Indre-et-Loire") → a place
is not a qualitative refinement: route it to `leadbay_adjust_audience({locations: [...]})`
and say why. If a qualitative part ALSO remains, continue to PHASE 1 with that part —
do not drop half the request.
- **A qualitative refinement** → continue to PHASE 1, passing the STRIPPED text and never
the raw instruction.

**One workspace = one country — a country name is NEVER a location filter.** The admin-area index holds no country nodes, so `"France"` matches the *commune of Francs* and `"United States"` matches *Statesboro*: the call is silently fenced to one village and every conclusion from it is wrong. City AND country named? Keep the city, drop the country.

**On `code: "COUNTRY_LEVEL_LOCATION"` read `country_locations[].axis` and `[].kind` — the recovery differs per case and they are NOT interchangeable, and do NOT retry with another spelling or a nearby city.**

`axis: "include"`:

- `home_country`, or "nationwide" / "everywhere" → drop that ONE value. Omit the geo argument (`city` / `locations` / `location_ids`) only if nothing else was on it — then the result covers the whole workspace. If other values remain, keep them and describe the result as those places.
- `foreign_country` ("leads in France" on a US workspace) → **unsupported, not unfiltered.** Do NOT re-run without the argument: whole-workspace results are US leads and answer nothing about France. Say the workspace holds only its own country's companies.
- `supranational` ("EU", "EMEA") → name what the workspace covers, then offer the whole-workspace view as an explicit choice rather than assuming it.
- `country_indeterminate` (custom/staging backend) → its country is unknown, so claim nothing about what it holds.

`axis: "exclude"` reverses all of that — **never "omit the argument"**, which returns the very companies the user asked to remove. Excluding this workspace's own country would empty it; excluding any other country is a harmless no-op. Either way drop the value and ask what to carve out instead.

On a lens-WRITING tool (`new_lens`, `adjust_audience`, `update_lens_filter`) write NOTHING, with no re-call in any form: when the country was the only scope, and for ANY non-`foreign_country` `exclude` hit however much else came with it — dropping it and writing the rest inverts the ask.

**Never infer WHICH country this workspace serves from the user's wording** — "the whole US" does not make it one. Read `_meta.region` on any tool result — it outranks any recalled memory; on `custom`, claim nothing.

Place names never go in `keywords`, `sectors` or `refine_prompt` — text matches, not geo filters.


# PHASE 1 — REFINE (only when PHASE 0 classified the instruction as qualitative)
Call `leadbay_refine_prompt` with `prompt=<the STRIPPED instruction from PHASE 0, Step 1>` — the text with any country phrase removed, never the raw instruction.

# PHASE 2 — CLARIFICATION ROUND-TRIP (if needed)

Expand Down
Loading
Loading