---
name: ginse-replacement-scan
description: Run a private one-time macOS and Chrome/Chromium usage audit, then automatically compare up to ten recognized web and native tools with agent-native replacements.
metadata:
  author: ginse
  version: "0.6.0"
---

# Ginse private agent-native replacement scan

After one informed yes/no consent, audit the user's recent tool usage locally and automatically compare up to ten recognized web and native tools with agent-native alternatives from Ginse. Return the completed result without asking the user to identify, confirm, or estimate their tools. Every completed scan must contain exactly one personal next action whose kind is switch, augment, delegate, or keep, even when inventory, matching, AX, or duration evidence is incomplete. Highlight at most three defensible, usage-weighted wins when they can be quantified. Do not install anything, create an account, purchase a product, or switch the user's tools.

## Non-negotiable privacy boundary

- Raw browser history never leaves the device and never appears in the model transcript. Never print page titles, URL paths, queries, fragments, profile names, Chrome databases, application paths, or unknown domains.
- Before the single upfront consent, make no request containing a detected product name, domain, URL, job, or inventory. After consent, the application payload sent to Ginse may contain only a recognized canonical product name and its locally inferred primary job; the form or API payload sent to Ora and Is It Agent Ready may contain only a non-null provider-scoreable product origin. The same applies to the one chosen alternative per incumbent. Never send a raw inventory or a free-form current-tool name. Never transmit visit counts, active days, durations, weekly-use estimates, last-used dates, source labels, unknown domains, raw history, or the inventory as a bundle. Ordinary HTTPS request metadata is handled by each provider's privacy notice.
- Use a mode-0700 temporary directory, read copied databases only, and delete every temporary artifact in a finally/trap path. Do not create permanent files, daemons, extensions, scheduled jobs, or background processes.
- After consent, make one best-effort read of the current user's local private Screen Time app-duration store. Access only RMAdminStore-Local.sqlite through the validated Darwin user directory; never access RMAdminStore-Cloud.sqlite, knowledgeC.db, web-domain rows, account or family records, device identifiers, notifications, pickups, categories, or unknown bundle identifiers. Full Disk Access is broad macOS permission and must be granted by the user to the responsible host app; never self-grant, use sudo, reset TCC, or bypass a denial. An unknown private schema must fail closed to the Spotlight fallback.
- Do not access browser cookies, saved passwords, form data, document contents, clipboard contents, or window contents.
- Only inspect the last 30 days. Infer a conservative weekly-use estimate locally and label its basis and confidence; never claim that recency proves duration.
- The optional choice after the report is the only later privacy expansion. It may authorize two distinct exact payloads: a pending candidate submission and a catalog-only share card. The candidate payload is limited to its previewed public name, canonical product URL, API/CLI/MCP interface, core-job claim, and first-party evidence URL. The share payload remains limited to the previewed percentage, action kinds, and public Ginse catalog IDs. Neither payload may contain raw inventory, usage, history, identity, credentials, arbitrary fetched content, or a free-form incumbent name.
- Stop immediately if the user declines the single upfront scan consent. Do not add another gate before the finished report. The later candidate/share choice is separate; never submit a discovery or create a link without its explicit yes. If a lookup is unavailable, blocked, rate-limited, requires login, or presents a CAPTCHA, leave that component null and finish the report instead of pausing for user input. Never weaken these rules to complete the scan.

## Compatibility check

Check all of the following locally before asking for scan consent:

1. The device is macOS.
2. A local read-only shell and Python 3 with the standard-library sqlite3 module are available.
3. HTTPS fetching and visible browser control are available.

If local access is unavailable, say that a web-only agent cannot inspect a Mac and offer optional manual entry of up to ten tools. Manual entry is the only case where tool details may be requested; do not imply that a manual list came from device usage.

## Single consent — local inspection and limited lookups

Before reading any history or application metadata, explain the full flow in plain language and ask exactly one explicit yes/no question. The explanation must say that the scan will:

- inspect temporary read-only copies of the last 30 days of Chrome/Chromium history for recognized products, recent Spotlight application metadata, and—when the responsible host already has user-granted Full Disk Access—the current user's private local Screen Time app-duration store;
- explain that Full Disk Access is a broad macOS permission, that the reducer will never self-grant it, and that denied, disabled, missing, or unsupported Screen Time data falls back automatically to conservative Spotlight recency rather than zero usage;
- keep raw history, page details, unknown domains, usage observations, and the resulting inventory on the Mac;
- after local reduction, put only recognized canonical product names plus locally inferred jobs in Ginse application payloads, and only non-null provider-scoreable product origins in Ora and Is It Agent Ready form or API payloads, for the incumbent and one candidate alternative; when Ginse has no credible match, a bounded public search sends only the generic inferred job plus API/CLI/MCP terms and reads only first-party product evidence;
- delete temporary data after the report; and
- send one aggregate completion event whose body contains no tool, domain, job, usage, report, or device identifier; ordinary request metadata is handled under the Ginse privacy notice.

Use a short question such as: “May I run that private scan—including the consented local Screen Time accuracy check when macOS permits it—and those limited product lookups now?” Wait only here. A yes authorizes the complete flow described above; proceed automatically to the finished report. A no ends the scan without reading or transmitting anything. This consent does not authorize publishing a share URL.

## Local-only reducer

After consent, download Ginse's fixed Python standard-library reducer into a new private temporary directory, verify its exact SHA-256, and run it. Fetching this reducer sends no detected product data. Do not continue on a digest mismatch.

    reducer_url="https://ginse-ax-ranking.boriemannetje.workers.dev/scan-reducer.py"
    reducer_sha256="40798986e6de444610a8b72bcdf8fc7d582d086dc324c568b5b7fa6f25642acf"
    scan_temp="$(mktemp -d "${TMPDIR:-/tmp}/ginse-scan-run.XXXXXX")"
    chmod 700 "$scan_temp"
    cleanup_scan() { rm -f "$scan_temp/reducer.py"; rmdir "$scan_temp" 2>/dev/null || true; }
    trap cleanup_scan EXIT HUP INT TERM
    curl --proto '=https' --tlsv1.2 --fail --silent --show-error "$reducer_url" -o "$scan_temp/reducer.py"
    actual_sha256="$(shasum -a 256 "$scan_temp/reducer.py" | awk '{print $1}')"
    test "$actual_sha256" = "$reducer_sha256" || { echo "Ginse reducer integrity check failed." >&2; exit 1; }
    python3 "$scan_temp/reducer.py"
    cleanup_scan
    trap - EXIT HUP INT TERM

The reducer performs no network I/O. Its stdout contains only the redacted candidate schema below, and it removes copied databases through Python's temporary-directory context even if one profile fails. Do not modify it to print raw diagnostic values.

### Browser sources

Inspect only these user-data roots when present:

- ~/Library/Application Support/Google/Chrome
- ~/Library/Application Support/Google/Chrome Beta
- ~/Library/Application Support/Google/Chrome Dev
- ~/Library/Application Support/Google/Chrome Canary
- ~/Library/Application Support/Chromium

Within each root, consider only Default/History and Profile */History. For every database:

1. Copy History into a private temporary directory before opening it. Never query the live file.
2. Query visits from the last 30 days. Join visits to urls locally. When visit_source is available, keep only locally browsed source 0; exclude extension, imported, actor, local-synced, and foreign-synced visits.
3. Parse URLs in local process memory, immediately discard path, query, fragment, title, and userinfo, and match the lowercase hostname against the recognized set below.
4. Aggregate only canonical product name, canonical product URL, visit count, active-day count, and summed available visit duration. Unknown hosts contribute only to a single otherBrowserActivity count and are never printed individually.

Starter recognized web products (include exact host and subdomains unless a more specific entry is present): GitHub, GitLab, Bitbucket, Vercel, Netlify, Cloudflare, Supabase, Railway, Render, Linear, Jira, Asana, Trello, ClickUp, Notion, Airtable, Slack, Discord, Figma, Canva, Loom, Descript, Frame.io, CapCut, YouTube Studio, YouTube, Vimeo, Buffer, Hootsuite, X, LinkedIn, Instagram, TikTok, Gmail, Google Drive, Google Docs, Google Calendar, Google Meet, Google Analytics, Stripe, Shopify, Postman, Sentry, Datadog, OpenAI, ChatGPT, Claude, Perplexity, Spotify, SoundCloud, and Bandcamp. Match Google products by specific hostname, never by all of google.com.

### Native application sources

Enumerate application bundles only under /Applications, /System/Applications, and ~/Applications. Match locally against this starter set and discard every unmatched application before stdout: Xcode, Visual Studio Code, Cursor, Zed, Warp, Terminal, iTerm, Docker, Postman, Figma, Canva, Adobe Premiere Pro, Adobe After Effects, DaVinci Resolve, Final Cut Pro, CapCut, Logic Pro, Ableton Live, FL Studio, Pro Tools, GarageBand, OBS, Slack, Discord, Notion, Linear, Spotify, Google Chrome, and Chromium.

For recognized bundles, use Spotlight kMDItemLastUsedDate and include only apps used within the same last-30-day window. Omit apps whose last-used metadata is unavailable or older than the window and say how many recognized apps were omitted. Spotlight proves recency, not duration. Do not invent hours from it.

After the disclosed consent, the reducer also attempts the private local Screen Time accuracy source. It must discover the Darwin user directory through confstr, accept only the exact current-user-owned regular non-symlink path ending in com.apple.ScreenTimeAgent/Store/RMAdminStore-Local.sqlite, copy the main database plus present WAL/SHM sidecars, and open only that copy read-only. It may query only an allowlisted schema that yields bundle identifier, local usage day, and duration for the last 30 days. Immediately map recognized bundle identifiers to the native starter set and discard every raw row and unknown identifier. Never inspect the Cloud store, CoreDuet/Knowledge databases, domains, categories, accounts, family members, device identifiers, notifications, or pickups. If access is denied, Screen Time is disabled or empty, discovery fails, or the schema is unknown, finish with the Spotlight fallback and a generic warning. Missing Screen Time is never zero usage and never blocks the recommendation.

### Redacted stdout schema


    {
      "windowDays": 30,
      "candidates": [
        {
          "name": "recognized canonical name",
          "canonicalUrl": "recognized product URL or origin, or null",
          "scoreableOrigin": "provider-scoreable product origin or null",
          "sources": ["browser", "native"],
          "visits": 0,
          "activeDays": 0,
          "observedHours": null,
          "lastUsedDate": "YYYY-MM-DD or null",
          "inferredPrimaryJob": "conservative product-level inference",
          "jobConfidence": "low or medium",
          "estimatedWeeklyHours": 0.5,
          "estimatedWeeklyHoursBand": "display band or lower-bound label",
          "estimatedWeeklyHoursIsLowerBound": false,
          "durationEstimateUsable": true,
          "durationWarning": null,
          "usageEstimateBasis": "local observation or recency-only assumption",
          "usageConfidence": "low or medium"
        }
      ],
	      "otherBrowserActivity": 0,
	      "screenTimeStatus": "used | permission-required | unavailable | unsupported | empty",
	      "warnings": []
    }

Deduplicate the same product across web and native sources. Return at most ten recognized candidates from the combined web-and-native inventory. When both source types are present, reserve up to three slots for the most recently used native-only applications and at least one slot for the strongest browser-observed product, then fill remaining slots by active days, visits, available duration, and recency. A native-only app must not be discarded merely because it has no browser duration.

## Automatic local interpretation

Do not display an interim inventory and do not ask the user to confirm, annotate, or supply ten tools. Use every reducer candidate, up to ten, and continue immediately.

For each candidate, use the reducer's conservative product-level primary-job inference. Treat it as an assumption, not knowledge of the user's intent. Estimate weekly usage locally as follows:

- If private Screen Time and/or browser duration is available and durationEstimateUsable=true, convert the 30-day total to a weekly average and map it down to the conservative representatives 0.5, 2, 5, 11, or 15 hours for the bands <1h, 1–3h, 3–7h, 7–15h, and 15h+; label confidence medium. Treat 15h+ as a lower bound, not a precise 15-hour estimate.
- If browser duration exists but durationEstimateUsable=false, retain its warning, use the reducer's frequency-based usage band for prioritization only, and suppress numeric time-saved claims.
- If browser duration is unavailable, use active days and visits only as a frequency heuristic: 5h for at least 20 active days or 100 visits, 2h for at least 8 active days or 30 visits, otherwise 0.5h; label confidence low.
- For a native-only app, use 0.5h as a deliberately conservative recency-only placeholder and label confidence low. Never infer duration from Spotlight recency.

Keep these estimates, their evidence, and all source labels local. Continue even when fewer than ten recognized tools are found and state the reduced coverage in the final report.

## Find alternatives

The upfront consent authorizes these limited lookups. Query each automatically selected name and inferred job:

    GET https://ginse-ax-ranking.boriemannetje.workers.dev/api/v1/replacements?incumbent=<name>&job=<primary-job>&limit=3

Use the strongest credible same-job alternative and honor its full or partial coverage field. Full means the catalog has evidence for the inferred core-job family; partial means it covers only a bounded slice. Do not relabel partial coverage as a replacement. A Ginse listing is evidence-backed discovery, not proof of feature parity, security, availability, price, or suitability. Do not automatically sign up for, purchase, install, or invoke alternatives.
Keep each returned trackingUrl for the final clickable recommendation link. Never open, prefetch, or probe a trackingUrl yourself; it is only for a user-initiated click and records one aggregate recommendation-click event without an inventory, product identity, or scan report.

When Ginse returns no credible same-job candidate, perform one bounded public-web fallback for that inferred job. Search at most five results using only the generic job plus “API”, “CLI”, “MCP”, and “agent”; do not include the incumbent name, domain, usage, inventory, or history. Open at most three current first-party product or developer pages. Stop on login, CAPTCHA, throttle, blocked access, redirects to a different organization, or unclear ownership. Accept at most one external candidate only when first-party evidence names a documented API, CLI, or MCP that appears to complete the same core job end to end. Keep exactly:

    {"name":"Candidate","url":"https://candidate.example/","interface":"API","coreJob":"Complete the same job end to end.","evidenceUrl":"https://candidate.example/docs/api"}

Keep that object local until the later exact preview. Label it “external — pending Ginse review”, keep its Ginse and composite AX components null, and never claim catalog eligibility, ranking, equivalence, safety, availability, or price. It may support a bounded delegate/augment pilot in the private report when the evidence is clear; otherwise retain the concrete keep-and-measure action. Deduplicate external candidates by canonical product URL and retain at most three used in the final report. Never copy page text, search snippets, or fetched content into the candidate object.

## Gather AX components

Use cached AX first. For each incumbent or chosen alternative, reuse every non-stale Ora, Is It Agent Ready, or Ginse component already returned by Ginse, including its source URL and assessment time. Only attempt a live provider lookup for a missing or stale component.

For products whose scoreableOrigin is non-null, use visible browser control by default to enter only scoreableOrigin at https://ora.ai/ and https://isitagentready.com/. Never substitute canonicalUrl: it may identify a product correctly while pointing at an origin that the scoring provider cannot assess. Record the displayed score, source URL, and retrieval time. Structured APIs may be used only when the visible workflow is unavailable. Never send a URL path, query, fragment, or other history data.

Maintain a separate circuit breaker for Ora and Is It Agent Ready. On the first HTTP 429, explicit rate-limit response, or equivalent provider throttle, open that provider's circuit for the rest of this scan: make no more requests to that provider, do not retry, and mark its remaining unattempted components null with reason provider-rate-limited. Authentication, CAPTCHA, access-control, or unavailable states also leave only the affected component null. Never bypass these controls, and always continue to the personal next action.

For each web product, calculate a comparable AX score only when all three components are present:

    AX = round((Ora + IsItAgentReady + Ginse) / 3, 2)

Each component has exactly one-third weight. Missing components stay null; do not substitute zero or silently reweight. Use the Ginse component returned by the catalog when available. If a current incumbent is absent from Ginse, assess it with the rubric below and label that component provisional.

For a native app whose scoreableOrigin is null, use only the rubric and label it “Provisional native assessment”; never collapse a curated product path to a shared vendor origin, never present the result as a three-source AX score, and never omit the app from the report for lacking a provider-scoreable origin.

### Ginse rubric (100 points)

- Core job completed end to end by an agent: 30
- Human intervention avoided for the core path: 20
- Structured inputs, outputs, and state: 15
- Delegated authentication and least privilege: 15
- Deterministic errors, retries, and recovery: 10
- Current discovery, documentation, and evidence: 10

Cap GUI-only or undocumented automation at 35. Below ten approved human reviews, the Ginse component is provisional. At ten or more, use the approved human-review mean and label it review-backed.

## Calculate the personal agent-native percentage

This percentage is a separate personal stack metric, not the three-source AX score and not a judgement of the user's ability. Calculate it from every observed tool's Ginse agent-operability component, which is always either catalog-backed or a labeled local provisional rubric assessment. Never use the deprecated legacy agentScore, never substitute missing Ora or Is It Agent Ready components with zero, and never use a candidate alternative's score in the user's current-stack percentage.

Use the reducer's coarse weekly band representatives as local weights: <1h = 0.5, 1–3h = 2, 3–7h = 5, 7–15h = 11, and 15h+ = 15. Then calculate:

    agentNativePercentage = round(sum(currentGinseScore * usageBandWeight) / sum(usageBandWeight))
    methodologyVersion = "ginse-agent-native-v1"

Show the integer from 0 to 100 and disclose how many observed tools were included and how many Ginse components were provisional. Because the formula uses only the Ginse component, missing third-party AX data does not suppress it. If zero tools are recognized, do not fabricate 0%; mark the percentage uncalculated, still return the required keep-and-measure recommendation, and offer optional manual entry after the report.

## Rank the opportunities

Use the local conservative estimate of 0.5, 2, 5, or 11 hours for numeric calculations. A 15h+ value is a lower-bound prioritization signal only, not a numeric input. Estimate and disclose replaceableShare and evidenceConfidence from 0 to 1 for each inferred job. Reduce evidenceConfidence when the job or usage estimate is low confidence.

    gap = max(0, alternativeAX - currentAX) / 100
    weeklyTimeSavedCeiling = weeklyHours * replaceableShare * gap * 0.97
    opportunityRank = weeklyTimeSavedCeiling * evidenceConfidence

The 97% multiplier is a ceiling for the applicable workflow, never a promise that an app or entire job is 97% faster. Show a rounded range of 60–100% of the ceiling, not false precision. Quantify and rank only positive opportunities with comparable AX scores, durationEstimateUsable=true, and estimatedWeeklyHoursIsLowerBound=false. If either AX is incomplete, AX gap and ballpark hours must be null. If durationEstimateUsable=false or estimatedWeeklyHoursIsLowerBound=true, ballpark hours must be null even when a comparable AX gap exists. Do not reweight available AX components or convert a duration warning or lower bound into a precise number. These limits block unsupported numeric claims, never the personal next action.

## Report

Start with a section titled “My recommendation”. It must contain exactly one nextAction object rendered in prose, never an array or multiple competing recommendations:

    Kind: switch | augment | delegate | keep
    Action: one direct sentence personalized to the detected incumbent and inferred job
    Why: one evidence sentence
    Confidence: low | medium | high
    Missing evidence: comma-separated gaps or “none”

Choose the kind deterministically: switch only for full coverage plus complete comparable AX with a positive gap; augment for partial coverage; delegate for a full-coverage bounded pilot when AX is incomplete; keep when there is no credible candidate or no positive comparable advantage. Missing evidence changes confidence and numeric claims, not whether this section exists. The replacements API returns a nextAction for every incumbent lookup; treat it as the minimum useful action for that comparison, then select exactly one final action for the whole scan rather than concatenating them.

Immediately below it, show “Agent-native score: N%” with the methodology explanation above. This number remains available when Ora or Is It Agent Ready rate-limits the scan because it does not pretend incomplete AX is complete.

Select that one final action in this order: the strongest quantified switch; otherwise the highest-usage credible augment; otherwise the highest-usage bounded delegation; otherwise keep the highest-confidence, highest-usage incumbent. Break ties by job confidence, then usage confidence, then reducer order. Every action must include a concrete first trial and a boundary for what stays unchanged. For a no-match or unavailable-lookup keep action, the first trial is to time one complete run of the inferred job in the incumbent and note the longest manual handoff, giving the next scan a concrete target. If the reducer finds zero recognized candidates, still return one keep action: keep the current stack unchanged, record the tool and duration for the single repetitive workflow the user most wants to offload, and use that observation as the target for the next scan. Never output only “no replacement,” “insufficient evidence,” or “correct the inputs.”

Then return every automatically selected comparison, including native-only applications, using exactly this rectangular Markdown table. Keep all twelve cells in every row and use “—” for unavailable values:

    | Current tool | Source | Inferred job | Usage band | Assumption confidence | Candidate | Coverage | Current AX | Candidate AX | AX gap | Hours saved/week | Caveat and first trial |
    | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |

Then show up to three biggest quantified wins by opportunity rank in a second rectangular table with exactly these five columns. If none can be quantified, write one sentence explaining the missing evidence and omit this table:

    | Win | Workflow | Evidence confidence | AX gap | Ballpark hours saved/week |
    | --- | --- | --- | --- | --- |

Incomplete scores must never fabricate AX, gap, or hours. Catalog misses must never fabricate a candidate. Both still produce the one lowest-risk personal next action above.

Finally, confirm that temporary copies were deleted and list any privacy or coverage limitations. Never retain or upload the inventory. The first user-visible inventory must be this completed report, not a preflight questionnaire.

After the report, say that the user may optionally correct a product, job, or weekly-use estimate and ask for a rerun. This is an invitation, not a question or prerequisite, and must never delay the initial result.

## Completion signal covered by the upfront consent

After showing the finished report and confirming cleanup, send the already-disclosed aggregate completion event without asking another question. Send exactly:

    curl --proto '=https' --tlsv1.2 --fail --silent --show-error       -X POST -H 'Content-Type: application/json'       --data '{"event":"completion"}'       'https://ginse-ax-ranking.boriemannetje.workers.dev/api/scan-events'

## Optional candidate review and share card — separate explicit choice

Only after the completed report, cleanup, and completion event, prepare a one-line preview containing the calculated percentage and up to three ranked alternative public catalog app names and IDs with their action kinds. A recommendation may also identify one current app—or at most two when that single recommendation genuinely replaces both—but only when each current app has an unambiguous, eligible public Ginse catalog ID. Resolve that ID with an exact canonical-name match from the public catalog; if the match is missing or ambiguous, omit the replacement claim. Never infer an ID, use a domain as an ID, or send a free-form name.

The preview must show the exact public name and ID of every optional replacement, for example: “Agent Tool [catalog-agent-tool] (delegate; replaces Slack [catalog-slack]).” Explain that these replacement names will be public because their catalog IDs resolve to public catalog entries. Never include any other current-tool names, raw inventory, inferred jobs, usage, hours, AX components or gaps, history, identity, free-form report text, or device data. Explain that creating the link uploads exactly that allowlisted preview to Ginse, makes an unlisted public URL viewable by anyone who has it for 30 days, and that social sites may temporarily cache its preview.

If the final report uses any external candidate, add a separate “pending review” line for each one showing exactly its name, canonical product URL, interface, core-job claim, and first-party evidence URL. Explain that these exact public product fields—not the scan—will be sent as a distinct pending, unranked submission; human moderation and the existing agent-first admission policy still decide whether it ever enters the public index. External candidates never enter the scan-share payload.

Then ask one conditional question: “Submit those exact discoveries for review and create the catalog-only 30-day share link with exactly the previewed fields?” Omit either half when there are no external discoveries or no truthful catalog share. This is optional and is the only additional yes/no question permitted. A no changes nothing. A yes first authorizes one distinct request per previewed external candidate. Generate a fresh private 32–128 character URL-safe idempotency key for each candidate and reuse that key only when retrying its identical body:

    POST https://ginse-ax-ranking.boriemannetje.workers.dev/api/v1/submissions
    Content-Type: application/json
    Idempotency-Key: <fresh-high-entropy-key>

    {"name":"Candidate","url":"https://candidate.example/","interface":"API","coreJob":"Complete the same job end to end.","evidenceUrl":"https://candidate.example/docs/api"}

An existing canonical pending submission is success. A 409 means the key was reused with a different body; do not retry that key. Never send incumbent names, inventory, jobs inferred for incumbents, usage, history, identity, credentials, arbitrary page content, or scan-share fields to this endpoint.

When the approved preview also contains a truthful catalog share, the same yes authorizes exactly one separate JSON request containing an integer agentNativePercent, scoreMethodologyVersion="ginse-agent-native-v1", and one to three objects with position, kind, public Ginse catalog toolId, plus an optional replaces array of one or two exact public catalog IDs shown in the preview:

    POST https://ginse-ax-ranking.boriemannetje.workers.dev/api/v1/scan-shares
    Content-Type: application/json

    {"agentNativePercent":48,"scoreMethodologyVersion":"ginse-agent-native-v1","recommendations":[{"position":1,"kind":"delegate","toolId":"catalog-agent-tool","replaces":["catalog-slack"]}]}

Use only switch, augment, or delegate entries that name an actual returned catalog alternative; never pad to three, invent a tool, publish an external pending candidate, or publish a keep action. Omit replaces unless the exact public catalog names and IDs were included in the approved preview. Never send an empty replaces array, more than two IDs, a recommendation's own ID, raw inventory, or a free-form incumbent name. If no percentage or catalog alternative is available, explain that a truthful card cannot yet be created; the separately approved pending candidate request may still proceed. Return the shareUrl when created. Keep the returned revokeToken private and explain that it can invalidate the link early; never append it to the share URL.
