Why
PLEN-2378 — the cortex config-generation agent keeps shipping config.ts files that humans then need to hand-fix. The Linear issue calls out two specific gaps (scopes not looked up from official docs, region not detected in baseUrl), but reviewing six recent cortex PRs showed the same prompt-level blind spots producing predictable failure modes.
| PR | App | Manual fix the agent should have done itself |
|---|
| #22433 | onenote | Add required_scopes: ['offline_access','User.Read']; Microsoft response_mode/prompt params |
| #22965 | microsoft_dynamics_365_business_central | Drop .default mixed with explicit scopes; drop Application-only scopes (auth-code flow is delegated-only) |
| #22522 | logfire | Verify region host pattern (api- vs logfire-), correct path prefix, constrain region via evalFields conditional |
| #23100 | iterable | Stop using brittle region.includes('eu'); dedupe host construction |
| #23166 | constant_contact | token_request_auth_method: 'basic' + same on refresh |
| #22459 | tienda_nube (3 unfixed Bugbot bugs) | fields.access_token not fields.bearer_token; {app_id} is not a framework placeholder |
What
Tightens both prompts so the agent produces these patterns on the first attempt.
cortex/agents/config_generator/researcher/prompt.py
- PHASE 3 — Scope handling. Replace one bullet with a five-step process: locate the official scope reference, pick
common_scopes carefully, derive required_scopes (offline_access + the test-endpoint scope), capture scope_separator, and apply provider-specific rules (Microsoft .default exclusivity + delegated-only auth-code rule; Google access_type=offline).
- PHASE 4 — Base URL, region, environment. Replace one bullet with explicit instructions to scan for data-residency/region/env variation, verify the host pattern by scraping each region's API reference (the logfire failure mode), constrain
region_values to the literal accepted tokens, and require the test_endpoint to follow the same dynamic pattern.
- Output schema gains
required_scopes, token_request_auth_method, refresh_request_auth_method, extra_authorization_params, region_values, field_defaults, field_descriptions.
- Anti-patterns 6-10 added: skipping
required_scopes, assuming static base URL, free-form region, missing Microsoft pattern, missing Basic auth on token endpoint.
- Coverage validation updated to enforce all of the above.
cortex/agents/config_generator/prompt.py
<json_to_config_mapping> now emits required_scopes, token_request_auth_method/refresh_request_auth_method, and merges extra_authorization_params into authorization_params.
base_url_dynamic mapping now produces a full region-with-evalFields-conditional example so the agent stops emitting brittle string-builders.
- New
<oauth2_field_access> section - in OAUTH2 mode the auto-injected token is fields.access_token, not fields.bearer_token (fixes the tienda_nube failure class).
- New
<oauth2_provider_patterns> section - Microsoft / Google / Zoho-style cookbook entries.
- New
<templating_critical> section - {client_id} and {{client_id}} are NOT framework placeholders; URLs must be plain TS string literals or (fields) => ... functions.
- Researcher JSON schema in the parent prompt updated to mirror the researcher's new output.
How to Test
- Rendered both prompts (they're f-strings) to confirm no
KeyError / unintended {...} interpolation; both produce intact strings (parent ~30 KB, researcher ~14 KB).
ruff check and ruff format --check clean on both files (config from repo's ruff.toml).
- Spot-checked the new guidance against every PR in the table above - each manual commit message maps to a specific new rule in the prompt.
Recommended follow-up before merging: trigger the agent on one Microsoft app (Graph-based) and one region-segmented app (e.g. a new EU/US SaaS) and confirm the first-pass config.ts no longer needs the patterns we just codified.
Pre-Review Checklist
Notes
- Docs-only / prompt-only change - no runtime behaviour modified.
- Worth coordinating with the bug-fixer agent so it doesn't auto-undo
required_scopes or the evalFields conditional when it lints generated configs.