eximagent

star 2

Trade-intelligence CLI for coding agents. Buyer/importer/distributor discovery, B2B lead gen, contact enrichment, cold outreach with stage tracking, tariff + HS-code + corridor + country lookups, OFAC sanctions screening, per-company negotiation memory, company-profile extraction from any website, raw-markdown crawl, product/facility image extraction for multimodal hosts, bulk processing with auto-pick. Use whenever user mentions eximagent/this CLI/the trade CLI, or asks: find buyers / importers / distributors, look up tariffs, what HS code, sanctions check, draft cold outreach, what trade duties apply, tell me about this company website, enrich N companies, crawl these websites, show/list/manage my saved collections or corridors or templates or knowledge base, my trade prospect lists, or any export/import/international-trade task. Invoke `eximagent <cmd>` for every step; auth via OAuth device flow or PAT.

EximAgent By EximAgent schedule Updated 6/9/2026

name: eximagent description: "Trade-intelligence CLI for coding agents. Buyer/importer/distributor discovery, B2B lead gen, contact enrichment, cold outreach with stage tracking, tariff + HS-code + corridor + country lookups, OFAC sanctions screening, per-company negotiation memory, company-profile extraction from any website, raw-markdown crawl, product/facility image extraction for multimodal hosts, bulk processing with auto-pick. Use whenever user mentions eximagent/this CLI/the trade CLI, or asks: find buyers / importers / distributors, look up tariffs, what HS code, sanctions check, draft cold outreach, what trade duties apply, tell me about this company website, enrich N companies, crawl these websites, show/list/manage my saved collections or corridors or templates or knowledge base, my trade prospect lists, or any export/import/international-trade task. Invoke eximagent <cmd> for every step; auth via OAuth device flow or PAT."

eximagent — trade-domain CLI for coding agents

Install

If the eximagent binary is not already on PATH, install it first — one command, no runtime to set up.

macOS / Linux:

curl -fsSL https://cli.eximagent.ai/install | sh

Windows (PowerShell):

irm https://cli.eximagent.ai/install.ps1 | iex

Then authenticate with eximagent login (OAuth device flow) or eximagent login --token <PAT>, and verify with eximagent whoami. The installer also drops this skill into the host agent's skill directories.

Quick start

  1. eximagent whoami — confirm auth (run eximagent login if it fails).
  2. eximagent profile get — see the operator profile that grounds every later turn.
  3. eximagent hscode search --query "<product>" — disambiguate HS code if the user did not give one.
  4. eximagent search run --product "<product>" --location <country> (preview) → --confirmed to start.
  5. eximagent collection get --name <name>eximagent enrich company --url <url> for the standouts.
  6. eximagent enrich contacts --collectionId <id> (filter-free first pass) → eximagent email draft --dry-run → confirm → eximagent email send --confirm.
  7. Stuck? eximagent collection analyze --collectionId <id> --question "<plain English>" ranks with reasoning.

Intent map — plain-language user phrase to canonical command

User says Canonical command Why
"find buyers / importers / distributors" search run buyer discovery
"help me understand this company" enrich company per-company deep crawl + summary
"find employee contacts" / "find decision makers" enrich contacts filter-free people search; recall-first
"find procurement people" enrich contacts then employees filter --departments procurement discover wide, narrow after
"rank these by size / fit / strategic priority" collection analyze --question "..." LLM ranking with auditable evidence per rank
"re-check this person's email" enrich contact --employeeId <id> single-row re-verify
"look up duties / tariff" tariff first, trade lookup --type ... fallback structured trade DB
"what HS code matches X" hscode search --query X HS disambiguation
"screen against sanctions" sanctions check --name X OFAC SDN
"save this trade lane" corridor save reusable corridor
"draft outreach to these" email draft --dry-run preview-first
"send all" email send --confirm flush with countdown
"show / list / manage my saved " <kind> list (server-side) NEVER search local files

Read past this point only when the quick-start chain leaves a question unanswered. The deeper material below explains every command, doctrine, error code, stream protocol, and workflow-state primitive.

You have eximagent, a CLI of trade-domain primitives. Use it for buyer discovery, trade research, company enrichment, contact enrichment, outreach drafting, sanctions checks, corridor management, raw-page crawls, image-rich multimodal outputs, and trade-memory tasks.

You are the orchestrator. eximagent is a dispatcher, not an autonomous workflow engine. Each command does one thing; your job is to choose the right order, batch by default, preview expensive steps, and keep the user out of bad runs.

What this CLI is best at

  • Fast first-pass buyer discovery from a vague prompt
  • HS code and tariff research
  • Building collections of trade prospects
  • Lightweight company-level enrichment from websites (structured + image-bearing)
  • Raw-markdown crawl of any website with caching
  • Bulk processing of large lists (companies, URLs, HS queries) in a single call
  • Drafting outreach once the target list is already clean

What this CLI is not good at by itself

  • Fully trustworthy contact data — you must respect confidence tags
  • Clean send-ready outreach lists without review
  • Resolving exact LinkedIn company URLs from raw company names at scale (auto-resolve helps; not perfect)
  • Anything outside the trade-domain surface

Treat eximagent as a strong discovery and enrichment helper. The data it returns is honest about its own confidence — read the tags and speak about each level accurately.

Golden path

Use this order unless the user explicitly wants something else:

  1. Ground in auth and profile
  2. Clarify product, market, and HS code if needed
  3. Run buyer search (preview → confirm → stream)
  4. Inspect results and shortlist
  5. Enrich company data on the shortlist (enrich company)
  6. Enrich contacts only for validated targets (enrich contacts)
  7. Draft outreach (email draft --dry-run first)

Skipping the shortlist step is the most common waste of budget and time.

Decision tree — if the user asks X, do Y

  • Find buyers / importers / distributorsprofile get to ground → clarify product + market + HS → hscode search if HS unknown → --dry-run search run preview → confirm → search run --confirmed (capture runId from the kickoff response) → stream --run-id <runId> and BLOCK until the terminal complete event before reading rows
  • Look up tariff → if HS is known: tariff --exporter --importer --product; otherwise hscode search first
  • Custom duties / NTM measures / remediestrade lookup --type duties|taxes|remedies|ntm|all
  • Identify a company from a namecompany --name "..." (single) or --inputs file.ndjson (bulk)
  • Profile a websiteenrich company --url ... (single) or --inputs file.ndjson (bulk). For just raw markdown without structuring: crawl --url ...
  • Screen against sanctionssanctions check --name "..." or --inputs names.ndjson
  • Draft outreach → verify list quality first, then email draft --dry-run → user confirms → email send --confirm
  • Show me / my / saved / existing collections|corridors|templates|kb → these are SERVER-side, owned by the authenticated user. NEVER search the local filesystem, session state, or temp dirs for them. Call the command directly: collection list / corridor list / template list / kb list. "saved"/"my"/"existing" never means local files.
  • Multimodal "what do these companies actually sell?" → bulk enrich company for the list → pass the returned keyFacts.images URLs to your host's vision tool
  • A list of N companies / URLs / HS queries → ALWAYS use --inputs bulk shape, never loop
  • Who actually ships / imports / exports a productproduct shipments --hs_code <code> or shipments search --hs6 <6digit> --dest <iso2> — real per-shipment customs records, not a model guess
  • A company's real shipment historycompany shipments --name "<company>" (matches exporter or importer)
  • Trade flowing on a route / laneroute shipments --origin <iso2> --dest <iso2>
  • Price / value evidence for a productprice shipments --hs_code <code> [--min_weight_kg N]
  • One shipment's full record or raw provenanceshipments get --id <recordId> / evidence show --id <recordId>

Trade-shipment records

shipments, company/product/route/price shipments, and evidence show query actual per-shipment customs + bill-of-lading records — hard evidence of who shipped what, where, when, and (where reported) at what value. Use them when the user wants real trade activity, not website inference. Reference companies by name (company shipments) or products by HS code / 6-digit prefix; filter routes by ISO-2 countries.

Every shipment response carries a coverage envelope: {coveredCountries[], periodStart, periodEnd, status, confidenceLevel, completenessRatio, usageGuidance, blindSpot}. Read it before drawing conclusions — status: covered is strong evidence; partial/limited is directional only; unavailable means there is no usable data for that query or period, so do not assert absence of trade. Surface the coverage honestly to the user instead of overstating completeness.

Trade-intelligence signals (use these for any number, not raw rows)

For any market / buyer / price / volume / concentration / recurrence QUESTION, call a signal verb — never page raw shipments search rows and aggregate them yourself. shipments search caps at a 1000-row page (browsing only); a metric built from that page is wrong. The signal verbs aggregate server-side over the FULL matching corpus and return a small business-ready result:

  • shipments market-signals --hs6 <code> --dest <iso2> — is this market attractive? shipment count, unique buyers/sellers, avg+median price/kg, top5 buyer share (concentration), month-over-month volume + price direction.
  • shipments buyer-recurrence --hs6 <code> --dest <iso2> — which buyers are durable accounts? active months, recurring/new/returning counts, retention, repeat-shipment ratio, per-buyer scale. This ranks the outreach shortlist.
  • shipments price-trend --hs6 <code> --dest <iso2> — where are prices heading? monthly avg/median/p25/p75/stddev price/kg + MoM change. Sets negotiating posture.
  • shipments route-signals --hs6 <code> --dest <iso2> — which origin→destination lanes lead the market, ranked by traded value.

All four scope with --hs6 OR --dest (same arg names as shipments search) plus optional --origin/--source/--from/--to (months YYYY-MM). Each response's nextActions chain the sibling verbs with valid flags — follow them. Lead the user with the commercial read (concentrated vs broadening, rising vs falling, who recurs), not the data source.

Analyze the ENTIRE database — two paths, in this order:

  1. Push the computation down (default). analytics query (structured groupBy × measures × filters) and analytics sql (guarded read-only SELECT) aggregate server-side over the FULL corpus and return a small result — you read the answer, not the rows. This is almost always what "analyze the whole db" needs. Read analytics catalog first for the schema.
  2. Pull raw rows only when you truly need row-level data. Both analytics query and analytics sql page the entire result set: each full page returns a nextActions next-page command (cursor) you follow until empty. For a large dump, use --out <file> [--format ndjson|csv] — the CLI auto-pages the whole result to disk and prints only a summary; then analyze the file programmatically (duckdb, jq, pandas) and read only your computed aggregates into context. NEVER read a multi-thousand-row dump into your context — query the file with code.

Drill-down on a specific shipment: shipments get --id <recordId> --view detail|logistics|financials|parties|evidence projects richer fields; evidence show --id <recordId> --normalized returns the English-normalized semantic fields alongside the raw source record. The 24-field summary view stays the default — request a wider view only when the user needs that depth.

Golden trade-intelligence chain: market-signals (is it attractive?) → buyer-recurrence (who are the durable accounts?) → price-trend (what posture?) → route-signals (which lane?) → shipments get --view/evidence show --normalized (verify one account) → enrich the shortlist for outreach only once the trade-intelligence picture is clear.

Every command is eximagent <category> [<subcategory>] <verb> [--flag value ...]. The exim prefix is optional:

eximagent profile get             # preferred, agent-natural
eximagent exim profile get        # also works (explicit)

Args are camelCase across the surface (exporterCountry, hsCode, businessType). Kebab-case (--hs-code) is accepted as an alias.

Exit codes: 0 success / 1 recoverable (retry with backoff) / 2 fatal (surface to user) / 64 usage error (fix the call).

Network: every command makes an HTTPS call to the EximAgent server, so the CLI needs outbound network on port 443. If a call fails with a connection/socket-blocked error (e.g. Windows connectex … forbidden by its access permissions), it's THIS environment blocking egress, not the server. Enable network for the run — under codex/a sandbox network is usually off by default, so re-run with it enabled (e.g. codex --dangerously-bypass-approvals-and-sandbox); behind a corporate proxy set HTTPS_PROXY; or allow the EximAgent host through firewall/antivirus.

Universal flags

  • --inputs <path|-> — bulk input: NDJSON list, one entity per line. Server processes the batch with bounded concurrency. Output: one streamed NDJSON document covering the whole batch.
  • --dry-run — preview only; sets confirmed=false + dryRun=true server-side. Safe wrapper for any billable / irreversible command.
  • --profile <name> — switch saved account. Same as EXIMAGENT_PROFILE=<name>.
  • --strict — single-input only: opt back into the blocking-candidates flow on ambiguous input. Default is auto-pick.
  • --output yaml|table|json — output format (default: JSON / NDJSON).
  • --stream — NDJSON stream events for long-running commands.
  • --out <file> [--format ndjson|csv] — bulk export for analytics query / analytics sql: auto-pages the ENTIRE result set to a file (10000 rows/page), printing only a small summary (rowCount, pages, columns, 3-row sample, byte size) to your context. Never streams the whole result into your context.
# Preview a search without burning credits:
eximagent --dry-run search run --product "<product>" --location DE --hsCode 090111

# Bulk: one tool call enriches all rows from an NDJSON file
eximagent enrich company --inputs companies.ndjson

# Multi-account:
eximagent --profile client-a whoami

Clarification-first — for single-shot human prompts

The user often speaks in vague human-like prompts ("find me some buyers", "send outreach", "what's the tariff"). Your job:

  1. Ask back before guessing. If a required arg is missing or ambiguous, ask ONE concrete question, then wait. Never invent product names, target countries, HS codes, or recipient titles.
  2. Run eximagent profile get first to ground in user defaults (product, targets, signature, incoterm, timezone).
  3. Preview billable / irreversible calls with --dry-run and present the plan + expected cost before confirming.
  4. Never blind-retry INVALID_ARG. That is your bug; read error.details.expected and did_you_mean, fix the call shape.

Worked example — vague prompt → clarify → execute

User: "find me some buyers"

eximagent profile get

If profile is empty ({exists:false, profile:null}):

You (to user): "Quick — what product are you exporting, which country market are you targeting, and the HS code if you know it?"

User: " to "

eximagent hscode search --query "<product>"

Pick the right HS code with the user. Then preview:

eximagent --dry-run search run --product "<product>" --location <CC> --hsCode <code> --direction buyers

After explicit user "go" — kick off the run, then BLOCK on its terminal event before reading rows:

RID=$(eximagent search run --product "<product>" --location <CC> --hsCode <code> --direction buyers --confirmed --output json | jq -r '.data.items[0].runId')
eximagent stream --run-id "$RID"   # blocks until terminal {kind:"complete"}

Cold start (every fresh session)

eximagent whoami      # verify auth
eximagent profile get # ground in user defaults

If profile is empty, gather business basics from the user and profile extract --from text --utterance "..." before any large workflow.

Token economy — never loop tool calls over a list

Every per-entity tool accepts --inputs <file|-> with one entity per NDJSON line. The server fans out with bounded concurrency and streams a single result back. One agent tool call → one streamed batch result → one context fill on your side.

The rule: for any list of more than ~5 items, use --inputs. Never loop a per-entity command over a list. Looping burns the host's token budget on N copies of the same prompt + N copies of the same tool-result framing.

# WRONG — burns token budget per row:
#   for url in $(cat list.txt); do eximagent enrich company --url "$url"; done

# RIGHT — one bulk call, one streamed result:
jq -R '{url: .}' list.txt | eximagent enrich company --inputs -

Bulk output is NDJSON: one {kind:"row", index, input, output, status, autoResolved?, alternatives?, costCents, durationMs} event per row, terminal {kind:"complete", rows, ok, autoResolved, failed, totalCostCents, totalDurationMs}. The terminal event is the summary the user wants — surface it.

Scale and batching rules

collection size safe pattern notes
1-10 single calls or bulk; either is fine tiny enough that loops do not hurt much, but bulk is still preferred for consistency
10-50 bulk only; shortlist before contact enrichment company-level enrichment ok across the whole set
50-200 bulk; ALWAYS shortlist before contact enrichment contact enrichment on a noisy 100+ list wastes budget
200+ bulk only; shortlist aggressively; consider --limit / --priority on enrich-contacts review the shortlist before billable enrichment

collection items list supports cursor pagination — fetch the whole collection without size limits. enrich contacts supports --priority high|medium|low, --limit N, --row-ids <csv>, --only-with-website, --max-cost-cents N to scope the run inside a large collection without creating a shortlist collection.

Bulk hard caps: --inputs rows max 1000 per call. Above that → INVALID_ARG. Split into multiple sequential bulk calls if the user has >1000 rows. Server-side concurrency caps at 25 workers; passing --concurrency 100 gets silently clamped (response started event surfaces concurrencyClamped:true).

Long-running ops (enrich contacts on 200+ rows, search run --confirmed=true): these can run for several minutes. The CLI prints a stderr heartbeat [eximagent] still working (Ns) every 30s so you know the call is alive, and retries transient failures with backoff. The per-call timeout defaults to 180s — raise it for long runs with EXIMAGENT_TIMEOUT_MS. DO NOT kill the call before the response lands.

run disambiguation: eximagent exim run status <runId> and eximagent exim run summary <runId> are top-level commands for any search run. eximagent exim search run is the buyer-discovery kickoff. Different verbs, same word — read the path carefully.

Preview→confirm binding: exim search run --confirmed=false returns previewToken: "pt_...". Pass that same token back as --previewToken on the --confirmed=true call. If any other arg drifts between the two calls (typo fix, HS code added, location reword), server rejects with INVALID_ARG: previewToken mismatch — re-run preview to get a fresh token.

Search-run lifecycle — the search MUST run, then BLOCK on its terminal event: search run is read-only discovery, not a billable send — it MUST execute (--confirmed=true, or via the preview→confirm pair). "Preview only" / "dry run" in the user's ask refers to the EMAIL draft (email draft --dry-run), never the search. Results land only at completion, so collection get / run status report running + totalCompanies: 0 until the run finishes — this is NORMAL, not a stall, not an empty result. You MUST eximagent stream --run-id <runId> (or poll run status <runId> every ~10-20s) and BLOCK until the terminal {kind:"complete"} event before enrich/draft/collection items list. NEVER re-run search run for the same intent (it starts and bills a separate run) and NEVER read company rows off the kickoff response.

Auto-pick on ambiguity (bulk default)

When an input is ambiguous (company name matches multiple plausible websites, HS prefix matches multiple chapters, country alias has alternates), the server picks the top-1 candidate by confidence and emits the row with autoResolved: true and alternatives: [{candidate, score, snippet}, ...] so you and the user can audit later.

  • Bulk runs NEVER block on candidates. They never emit a status:"candidates" event.
  • Single runs auto-pick by default. Pass --strict to opt back into the blocking-candidates flow when the user explicitly wants interactive disambiguation.
  • If a pick is wrong, the user asks the agent to redo just that row — overall productivity is far better than confirming every row up front.

Forward momentum — never stop after a single step

Every tool response carries nextActions: NextAction[] with the most-natural next steps for the result state. Each entry: {command, cost, label, rationale}command is the ready-to-run CLI line, cost is the spend tier of that step (free/low/medium/high), label is a one-line action name, rationale is why it follows. Your job:

  1. After ANY tool returns successfully, read nextActions[] BEFORE replying to the user.
  2. If exactly one action is free/low cost AND the user's original ask covers this step, auto-execute its command WITHOUT confirming.
  3. Otherwise surface nextActions[] to the user as a numbered pick list — one line each, using label + cost.
  4. NEVER say "I'm done" if nextActions is non-empty — explicitly state the open steps + ask the user to pick or say "skip remaining".

Example: search.run completes. The terminal response carries nextActions: [{command:"eximagent enrich company ...", cost:"medium", label:"Enrich the shortlist", rationale:"..."}, {command:"eximagent email draft --dry-run ...", cost:"free", label:"Draft outreach", rationale:"..."}]. User said "find buyers for ready for outreach" — that scope covers enrichment + drafts. Run each command in order.

Reporting discipline — driver must always know what you are doing

For ANY multi-step workflow (a chain of tool calls toward one user goal), you MUST emit five narration moments. These are non-negotiable — silent multi-step runs violate the platform contract.

  1. Plan card before the first billable step. Format: numbered step list with ETA + cost forecast per step, total ETA, total cost forecast, captured scope.
  2. Per-step ENTRY before each tool call: [2/4] enriching 30 companies on shortlist...
  3. Per-step EXIT after each tool returns: [2/4] done · 30 enriched · 28 with valid website · 2 unreachable · 78s · $0.61 cumulative
  4. Decision rationale when picking a non-obvious branch: "Picking enrich-company before enrich-contacts because contacts need company data"
  5. Final English summary as a colleague would report — not raw JSON. 2-3 sentences. What was done, key numbers, what user should know.

Skip-transparency: when you intentionally skip a step ([3/4 SKIPPED] enrich contacts (scope: shortlist-only)) — say so. Retry-narration: when a step partially fails and retries — say so. The driver should never have to guess.

Workflow state on collections

collection get / collection list / collection items list / run summary all carry enrichmentStatus: {company, contacts, drafts} (not-started / partial / complete). Use this to know whether enrich/draft has already happened on a collection — never re-derive, never re-ask the user.

Output protocol

  • stdout = NDJSON. One JSON object per line for streams, single object for one-shot.
  • stderr = short human breadcrumbs + structured {error:{code,message,details?}} on failure. Never parse stderr as data.
  • Long-running commands emit stage-level events ({kind:"stage", stage, completed, total, etaMs}) plus heartbeats so a quiet in-flight run is visibly healthy, then a terminal {kind:"complete"|"failed"}.
  • Use eximagent run status <runId> for an on-demand snapshot of any run and eximagent run summary <runId> for the per-stage counts + total cost when it finishes. run status carries live progress mid-run: companiesProcessed (agrees with collection get), expectedCompanies, percentComplete, stage, and lastHeartbeatAt — use these to track progress and to tell a live run (recent heartbeat) from a stale one, instead of re-running the search.

Confidence model — read every field's tag, speak accordingly

Every contact and company field returned by an enrichment tool carries {value, source, confidence}. Levels:

  • verified — upstream provider confirmed the contact. Present as fact: "Hans Schmidt, procurement manager at ."
  • extracted — pulled from crawled markdown via regex or model inference. Candidate data: "An email matching name@<company>.example was found on their site." Never call it verified.
  • heuristic — derived from secondary signals (LinkedIn company-page activity, page-context inference). Suggestion: "Likely a procurement role based on LinkedIn signals."
  • inferred — model guess from context. Hypothesis: "Probably an importer of based on their about-page description." Always frame as opinion, not fact.

When summarizing a row to the user, lead with verified facts and qualify everything below verified.

Multimodal — image URLs in the output

Tool output carries images:

  • keyFacts.images: [{url, alt, hint}] — company-level images (products, facility, team, other) extracted from the crawled site, filtered for legitimate product/facility imagery.
  • sellingProducts[i].imageUrls / buyingProducts[i].imageUrls — per-product photos when the page associates them.

If your host model is multimodal, route the image URLs directly to its vision tool before describing in text. This is the highest-bandwidth signal for "does this company actually do what their text claims".

# Example agent flow:
# 1. eximagent enrich company --inputs shortlist.ndjson  → rows with keyFacts.images[]
# 2. for each row, host's vision tool reads the image URLs
# 3. agent answers "yes this looks like a specialty <product> manufacturer" with image-grounded evidence

Anti-pattern: do NOT paste image URLs to the user as text-only links and ask them to open. Feed images to vision. Phase 1 stores image URLs only (no byte storage); plan around source-page rot by re-enriching when needed.

State and references — bare name or id

Pass any collection, corridor, template, company, knowledge, product, or bookmark by its bare name or its id directly to the matching arg. The server resolves a UUID-shaped value as an Id, otherwise as a name. No sigil, no prefix.

eximagent collection get --collectionId "my-buyers-q2"
eximagent corridor remove --name "my-lane"
eximagent email draft --collectionId "my-buyers-q2" --templateName "cold-intro"

If a reference does not resolve, you get NOT_FOUND. Call the matching list command to discover real names, then retry. The current user profile is a singleton — use profile get.

Discovering existing state

There is no global "list everything" command. Use the per-kind list:

eximagent collection list
eximagent corridor list
eximagent template list
eximagent kb list
eximagent products list
eximagent reminder list
eximagent monitor list

Error recovery (typed — never blind-retry)

code retry? action
INVALID_ARG NO Your bug. Read error.details.expected + did_you_mean (and error.details.enum for enum args — those are the allowed values). Args are camelCase.
NOT_FOUND NO Reference does not resolve. Call the matching list command first, then retry.
UPSTREAM_ERROR YES Upstream provider 5xx/4xx. Exponential backoff, retry once. If still failing, surface traceId. Fall back to authoritative web search when the upstream is the only source.
RATE_LIMITED YES Wait per error.details.retryAfterMs, retry up to 3x.
BUSY YES Another action in-flight on same context. Wait + retry.
FORBIDDEN NO Auth failed. Surface "run eximagent login" to the user.
INTERNAL_ERROR NO Unexpected server fault. Surface traceId.

When to stop and ask the user

Pause and ask explicitly when:

  • The user's product, target market, or HS code is ambiguous and profile get does not resolve it.
  • A billable run >$1 estimated cost is about to fire and the user has not confirmed.
  • Multiple plausible company identities resolve and the user wants the right one before paying for enrichment (use --strict on single calls; in bulk, auto-pick proceeds and the user can audit autoResolved rows after).
  • email send is about to flush — never send without explicit user "yes" / "send" / "confirm".
  • The user's framing of "buyers" vs "sellers" is unclear in context.

In every other case, decide and proceed.

Anti-patterns

  • Looping a per-entity command over a list. Use --inputs bulk shape.
  • Enriching contacts on a 300+ raw collection before shortlisting. Always shortlist by priority or score first.
  • Treating extracted emails / phones as verified. Read the confidence tag.
  • Presenting image URLs to the user as text links. Feed images to your host's vision tool.
  • Sending email without explicit user confirmation.
  • Blind-retrying INVALID_ARG.
  • Asking the user "which one?" on every ambiguous bulk row. Auto-pick + audit after.
  • Inventing commands not in the surface below. If a command is not listed, it does not exist.
  • Using snake_case args (hs_code). Use camelCase (hsCode); kebab-case alias also accepted.
  • Invoking _admin/* commands. Operator-tier, hidden.

Recovery playbook

  • Collection appears empty mid-run (totalCompanies: 0 while status: running) → NORMAL, not failure. Results land only at the terminal complete event. stream --run-id <runId> or poll run status <runId> and BLOCK on terminal before reading rows. Do NOT declare failure, do NOT re-run search run.
  • BUSY on the user context → wait retryAfterMs, retry. Surface a one-line "in-flight elsewhere, retrying in Ns" breadcrumb.
  • Preview text contradicts intent--direction buyers|sellers makes the intent explicit. Re-issue the preview before paying.
  • Bulk row count smaller than input → check failed count + per-row status. Re-run only the failed indices.
  • enrich contacts returns 0 verified → fall back to company-level signals + manual review. Do not double down on the same call.
  • Source page rot on an image → re-enrich the company (crawl cache is 100d; image URLs refresh).
  • A wrong autoResolved pick → re-run that one row with --strict (single) and let the user pick from alternatives.

Minimum viable output per workflow

A "good" agent response includes these for each common workflow:

  • Buyer discovery → collection name, total companies, top 5–10 by score, data-quality caveat (drawing on confidence tags), recommended next step (shortlist + enrich).
  • Tariff lookup → corridor (exporter → importer), HS code, duty rate(s), source attribution, notes on remedies if any.
  • Company enrichment (bulk) → row count, ok / autoResolved / failed counts, total cost, 2–3 worth-mentioning highlights (specialty signals, scale signals, image-grounded confirmations), recommended next step.
  • Outreach draft → recipient count, subject + preview of one draft, "ready to send?" confirmation prompt.
  • Sanctions check → hit / no-hit, program (OFAC SDN / SDGT / etc.), alias matched, advisory caveat.

Tooling expectations

eximagent is not a complete workflow tool. Reach outside the CLI for:

  • Spreadsheets for human review of shortlists and exports. CSV-to-NDJSON: jq -R '{url: .}' < list.txt | eximagent ... --inputs -.
  • Web validation when an autoResolved pick looks suspicious — open the alternative URLs in your host's browser tool.
  • Manual review for contact-extraction noise before any outreach run on extracted contacts.
  • Vision tool for image URLs from any enrich / crawl output (multimodal hosts only).

Reliability notes

  • Buyer discovery surfaces some non-buyer pages — confidence tags + shortlist step are the filter.
  • Extracted emails / phones may be noisy — describe them as candidate data until verified.
  • Contact enrichment may return 0 verified contacts even on legitimate companies. Fall back to company-level signals.
  • Long batch operations may have failed rows even when the batch completes — read failed count + per-row status and re-run the failures with the same --inputs.

Recommended workflow patterns

Buyer discovery

eximagent profile get
eximagent hscode search --query "<product>"
eximagent --dry-run search run --product "<product>" --location <CC> --hsCode <code> --direction buyers
RID=$(eximagent search run --product "<product>" --location <CC> --hsCode <code> --direction buyers --confirmed --output json | jq -r '.data.items[0].runId')
eximagent stream --run-id "$RID"   # blocks until terminal {kind:"complete"}; only then read rows

Shortlist before enrichment

eximagent collection items list --collectionId "<name-or-id>" --priority high --limit 25

Or scope enrich-contacts directly inside the large collection:

eximagent --stream enrich contacts --collectionId "<name-or-id>" --priority high --limit 25 --titles "Procurement,Buyer"

Bulk company enrichment from a CSV/spreadsheet

jq -R '{url: .}' company-urls.txt | eximagent enrich company --inputs -
# one bulk call, one streamed result, image URLs included per row

Raw markdown of a list of websites

jq -R '{url: .}' urls.txt | eximagent crawl --inputs -

Outreach last

eximagent email draft --collectionId "<name-or-id>" --brief "<angle>" --dry-run
eximagent email send --collectionId "<name-or-id>" --confirm

Common chains

Full outreach campaign (vague → confirmed)

eximagent profile get
RID=$(eximagent search run --product "<product>" --location <CC> --hsCode <code> --direction buyers --confirmed --output json | jq -r '.data.items[0].runId')
eximagent stream --run-id "$RID"   # blocks until terminal {kind:"complete"}
eximagent collection items list --collectionId "<name-or-id>" --priority high --limit 25
eximagent --stream enrich contacts --collectionId "<name-or-id>" --priority high --titles "Procurement,Buying,Purchasing,Sourcing"
eximagent email draft --collectionId "<name-or-id>" --brief "<your outreach angle>" --dry-run
eximagent email send --collectionId "<name-or-id>" --confirm

Trade Q&A inline

eximagent tariff --exporter VN --importer DE --product "<product>"
eximagent hscode search --query "<product description>"
eximagent company --name "<company name>"

Refine search

eximagent search refine --collectionId "<name-or-id>" --addLocation "Austria,Switzerland"
RID=$(eximagent search run --product "<product>" --location "DE,AT,CH" --hsCode <code> --direction buyers --confirmed --output json | jq -r '.data.items[0].runId')
eximagent stream --run-id "$RID"   # blocks until terminal {kind:"complete"}

Realistic worked examples

  • Buyers in a target market for a productprofile gethscode search --query "<product>"--dry-run search run --product "<product>" --location <country> --hsCode <code> --direction buyers → confirm → search run ... --confirmed (capture runId) → stream --run-id <runId> until terminal complete → shortlist --priority high --limit 25enrich company --inputs shortlist.ndjson → review → email draft --dry-run.
  • Importers for a different product → same pattern, --product "<product>", --hsCode <code>, --direction buyers --location <country>.
  • Tariff exposure for a product moving between two countrieshscode search --query "<product>"tariff --exporter <code> --importer <code> --product "<product>" → optionally trade lookup --exporter <code> --importer <code> --hsCode <code> --type all.
  • Multimodal triage of a bulk-enriched listenrich company --inputs companies.ndjson → for each row.output.keyFacts.images, route URLs to host vision tool → answer "which look like specialty roasters" image-grounded.

Known limitations

  • linkedin lookup works best with canonical LinkedIn company URLs. Auto-resolve from company name or website URL is supported but not always correct — provide a canonical URL when you have one.
  • enrich contacts is collection-scoped; subset is via the row-subset flags inside that collection, not arbitrary cross-collection selection.
  • Image extraction is URL-only in Phase 1; if the source page rots, re-enrich.
  • --strict is single-input only.
  • The crawl cache is 100d; for fresher data, the cache key is the canonical URL.
  • Long bulk runs respect upstream rate limits; concurrency defaults to 10 and reduces under upstream pressure.

What not to do

  • Do not guess product, market, HS code, titles, or send timing.
  • Do not blind-retry INVALID_ARG.
  • Do not parse stderr as data.
  • Do not send email without explicit user confirmation.
  • Do not assume collection rows equal verified contacts — read confidence tags.
  • Do not assume extracted emails or phones are clean.
  • Do not run huge enrichments before creating a shortlist.
  • Do not loop tool calls over a list; use --inputs.
  • Do not invent commands not listed below.
  • Do not use snake_case args; use camelCase such as hsCode.
  • Do not call hidden _admin/* commands.

Command surface (auto-generated from REGISTRY)

eximagent analytics anomalies

Surface month-over-month momentum anomalies (spikes/drops) in a corridor before you ask — scope by --dest, --origin, and/or --hs6; flags months whose measure swings past the threshold. The analyst that works while you sleep.

  • --dest — Destination country to scan (ISO)
  • --hs6 — HS6 product to scan
  • --measure — Measure to watch: value_usd (default), weight_kg, shipment_count, ...
  • --origin — Origin country to scan (ISO)
  • example: eximagent analytics anomalies --dest CO --hs6 090111

eximagent analytics catalog

Get the trade-analytics semantic catalog — the dimensions, measures, filter operators, time windows, and example queries you compose an analytics query from. Always read this before composing a query; never guess column names. (no args)

  • example: eximagent analytics catalog

eximagent analytics query

Answer ANY analytic question over the full trade corpus — compose a structured AnalyticsQuerySpec (groupBy × measures × filters × orderBy × limit) from analytics catalog. Aggregates are dedup-correct over the entire matching corpus, never a row sample.

  • --spec (required) — AnalyticsQuerySpec JSON (limit up to 10000/page; add offset + orderBy to page through the ENTIRE corpus — nextActions returns the next-page command): {"groupBy":["hs6"],"measures":["value_usd","shipment_count"],"filters":[{"dim":"dest","op":"=","value":"CO"}],"orderBy":"value_usd","descending":true,"limit":1000,"offset":0}
  • example: eximagent analytics query --spec '{"groupBy":["hs6"],"measures":["value_usd"],"orderBy":"value_usd","descending":true,"limit":10}'

eximagent analytics sql

Escape hatch for analytic questions the structured query cannot express: run a read-only SELECT over the trade corpus. SELECT-only, table-allow-listed, no table functions, auto-LIMITed + time-bounded. Prefer analytics query; use this only for the long tail.

  • --limit — Max rows per page (default 100, max 10000)
  • --offset — Row offset for paging the full result set (use ORDER BY for a stable page order; nextActions returns the next-page command)
  • --querySql (required) — A single read-only SELECT over the trade tables (tradeData + signal tables)
  • example: eximagent analytics sql --query_sql "SELECT hs_6, count() FROM tradeData WHERE destination_country='CO' GROUP BY hs_6 ORDER BY 2 DESC"

eximagent collection analyze

Rank every company in a collection against a plain-language analytical question. Each rank carries a 0-100 score plus one-sentence reasoning grounded in auditable evidence (description, match reasons, trade-potential score). Composes evidence per company from the persisted collection rows, calls an LLM with structured output, returns ranked items.

  • --collectionId (required) — UUID of the collection to rank
  • --question (required) — Plain-language analytical question to rank against
  • --rankingCriteria — Optional explicit weighting hints
  • example: collection analyze --collectionId js7abc --question "Which of these companies look largest?"
  • example: collection analyze --collectionId js7abc --question "Rank by export readiness" --rankingCriteria "weight certificates 2x"

eximagent collection clone

Deep-clone a collection (copies all items + custom columns; status reset to draft).

  • --name (required) — Name for cloned collection
  • --sourceId (required) — Source collection ID
  • example: collection clone --sourceId <id> --name 'germany-q3-clone'

eximagent collection columns add

Add an AI column to a collection. Per-row cells are populated by a follow-up streaming pass.

  • --collectionId (required) — Target collection ID
  • --label (required) — Column label (display)
  • --outputType enum: text|classification|score — Output cell type (defaults to text)
  • --prompt (required) — Per-row prompt; agent fills cells using company context
  • example: collection add-column --collectionId <id> --label 'Reply likelihood' --prompt 'Score 0-100 based on …' --outputType score

eximagent collection columns run

Populate per-row AI cells for an existing column. Sequential call per company; idempotent.

  • --collectionId (required) — Target collection ID
  • --columnId (required) — AI column ID (returned by columns add)
  • example: collection columns run --collection-id <cid> --column-id reply-likelihood-l8r2

eximagent collection create

Create an empty collection (manual outreach list, no pipeline run). Use this when the user wants to start a list to add companies/contacts to manually, OR bind a default email template, WITHOUT running the search pipeline. For autonomous buyer discovery use search run instead.

  • --businessType enum: export|import — Trade direction: 'export' (user sells) or 'import' (user buys). Default 'export'.
  • --description — Free-text purpose
  • --name (required) — Collection name or id
  • --templateName — Default outreach template name (must exist — discover via template list)
  • example: collection create --name q2-buyers
  • example: collection create --name q2-outreach --description "Q2 outreach push" --businessType export
  • example: collection create --name q2-list --templateName <template-name>

eximagent collection get

Get a collection by ID — METADATA ONLY (name, totals, priority counts, status). Does NOT return the company rows; for company rows use exim collection items list.

  • --collectionId (required) — Collection ID
  • example: collection get --collectionId <id>

eximagent collection items add

Add a company to a collection. Accepts either an existing companyId OR a companyUrl (auto-upserts into companies on the fly). Use companyName to give the upserted company a display name. Resolve collection by id or name.

  • --collectionId — Collection ID (e.g. mn7abc...)
  • --collectionName — Collection name. Resolved to ID server-side.
  • --companyId — company UUID. EITHER this OR companyUrl required.
  • --companyName — Company display name (used when upserting from companyUrl). Optional but recommended.
  • --companyUrl — Company canonical URL (e.g. https://<company-domain>). Triggers upsert into companies. EITHER this OR companyId required.
  • --priority enum: high|medium|low — Priority bucket
  • example: collection items add --collectionId <cid> --companyUrl https://<company-domain> --companyName "<Company Name>"
  • example: collection items add --collectionName germany-q2-prospects --companyId <id> --priority high

eximagent collection items filter

Filter rows in a collection: drop rows below minScore / not matching priority / without enriched mails. Idempotent — applies to current rows only.

  • --minScore — Minimum score (drop rows below)
  • --name (required) — Collection name
  • --priority enum: high|medium|low — Keep ONLY rows of this priority (drop others)
  • --requireMail — Drop rows whose company has no enriched mails (default false)
  • example: collection items filter --name germany-q2 --priority high
  • example: collection items filter --name germany-q2 --min-score 0.6 --require-mail true

eximagent collection items list

List the company rows inside a collection — name, score, priority, country, enriched mails, outreach stage. Use this to actually see WHO is in the collection after a search run completes. collection get returns only metadata (totals + priority counts); this returns the rows. Sorted by score descending. Target the collection with --collectionId (the id from search output, or the collection name) — same arg as every other collection/email/enrich command — or --name; defaults to your most-recent collection if neither given. Cursor-paginated (nextCursor), no size cap.

  • --collectionId — Collection to list — accepts the collectionId returned by search/recipe outputs OR the collection name. Same arg name as every other collection/email/enrich command. Use this when chaining from a recipe.
  • --cursor — Pagination offset (0-indexed). Feed the previous response.nextCursor to get the next page. Default 0.
  • --limit — Max rows to return per page (default 50, max 500). For full enumeration use nextCursor pagination.
  • --name — Collection name (alternative to --collectionId)
  • --priority enum: high|low|medium — Filter to this priority only
  • --profile — Saved ideal-profile name; when set, each row carries an explained fit score and the list is ranked by fit
  • example: collection items list
  • example: collection items list --collectionId <id-from-search-output> --priority high
  • example: collection items list --name germany-q2 --limit 20
  • example: collection items list --collectionId germany-q2 --priority high

eximagent collection items merge

Merge rows from one collection into another. De-duplicates by companyId. Optionally soft-deletes the source.

  • --from (required) — Source collection name (rows copied FROM here)
  • --into (required) — Destination collection name (rows merged INTO here)
  • --removeSource — Soft-delete source after merge (default false)
  • example: collection items merge --from <collection-a> --into <collection-b>

eximagent collection items remove

Remove a single row from a collection. Either pass --itemId directly OR pass --collectionId/--collectionName + --companyUrl to look up and remove the row for that company. Use collection items list to discover names + URLs.

  • --collectionId — Collection ID. Required when removing by companyUrl.
  • --collectionName — Collection name (resolved to ID server-side). Alternative to collectionId.
  • --companyUrl — Company canonical URL — resolves to the row in the named collection and removes it.
  • --itemId — Collection-item ID (direct row delete). Alternative to companyUrl.
  • example: collection items remove --itemId <id>
  • example: collection items remove --collectionName germany-q2-prospects --companyUrl https://<company-domain>

eximagent collection list

List user collections (most recent first). Tombstoned (soft-deleted) collections are excluded by default — pass --includeDeleted true to see them.

  • --includeDeleted — Include tombstoned (soft-deleted) collections (default false)
  • example: collection list
  • example: collection list --includeDeleted true

eximagent collection remove

Soft-delete a collection (tombstoned; mention chips render as deleted).

  • --collectionId (required) — Collection ID to soft-delete
  • example: collection remove --collectionId <id>

eximagent collection rename

Rename a collection.

  • --collectionId (required) — Collection ID to rename
  • --name (required) — New name
  • example: collection rename --collectionId <id> --name 'germany-q3'

eximagent collection similar

Find user's existing collections similar to a free-text query. Token-overlap scoring on (name, industry, targetCountry, query).

  • --limit — Max suggestions (default 5)
  • --query (required) — Free-text criteria description (industry, region, product, etc.)
  • example: collection similar --query "<industry> importers in <market>"

eximagent collection stats

Aggregate stats for a collection: totals, priority counts, conversion rate, runtime.

  • --name (required) — Collection name or id
  • example: collection stats --name germany-q2

eximagent collection update

Update collection metadata (description, businessType, industry, targetCountry). For rename use collection rename. For items use collection items add/remove.

  • --businessType enum: export|import — Trade direction
  • --collectionId (required) — Collection ID to update
  • --description — New free-text purpose / notes
  • --industry — New industry hint
  • --targetCountry — New target country
  • example: collection update --collectionId <id> --description "Q2 push, German roasters"
  • example: collection update --collectionId <id> --industry <industry> --targetCountry <country>

eximagent companies competitors

Competitive set: companies importing the same HS6 into the same reporting country, with shared-HS6 overlap and their volume vs this company

  • --country — reporting country (ISO 2) to scope the directory
  • --limit — max rows (1-1000, default 100)
  • --name — company name (used with --country when no tax id)
  • --taxId — company tax id (RUC/NIT/RUT) — the strong identity key

eximagent companies customers

Customers (importers this company sells to): each canonical id, shipments, value, shared HS basket, first/last seen, share of exports — ranked by value

  • --country — reporting country (ISO 2) to scope the directory
  • --limit — max rows (1-1000, default 100)
  • --name — company name (used with --country when no tax id)
  • --taxId — company tax id (RUC/NIT/RUT) — the strong identity key

eximagent companies graph

Local counterparty neighborhood: top suppliers + customers, competitor count, shared-supplier peers, supplier concentration (single-source risk)

  • --country — reporting country (ISO 2) to scope the directory
  • --limit — max rows (1-1000, default 100)
  • --name — company name (used with --country when no tax id)
  • --taxId — company tax id (RUC/NIT/RUT) — the strong identity key

eximagent companies list

Unique resolved companies per reporting country × HS6, each with its trade fingerprint

  • --country — reporting country (ISO 2) to scope the directory
  • --from — earliest month (YYYY-MM)
  • --hs6 — HS code (6-digit) to scope the market
  • --limit — max rows (1-1000, default 100)
  • --name — company name (used with --country when no tax id)
  • --origin — origin country (ISO 2) filter
  • --role enum: exporter|importer — limit to one role: exporter|importer
  • --to — latest month (YYYY-MM)

eximagent companies profile

Full trade fingerprint for one company: HS basket, corridors, counterparties, recurrence

  • --country — reporting country (ISO 2) to scope the directory
  • --name — company name (used with --country when no tax id)
  • --taxId — company tax id (RUC/NIT/RUT) — the strong identity key

eximagent companies suppliers

Suppliers (exporters this company buys from): each canonical id, shipments, value, shared HS basket, first/last seen, share of imports — ranked by value

  • --country — reporting country (ISO 2) to scope the directory
  • --limit — max rows (1-1000, default 100)
  • --name — company name (used with --country when no tax id)
  • --taxId — company tax id (RUC/NIT/RUT) — the strong identity key

eximagent companies trajectory

One company's value/shipment time-series by --bucket, with trend + peak months

  • --bucket — month|quarter (def month)
  • --country — reporting country (ISO 2) to scope the directory
  • --name — company name (used with --country when no tax id)
  • --taxId — company tax id (RUC/NIT/RUT) — the strong identity key

eximagent company

Company URL + profile + summary.

  • --address — Location signal (city, state, country)
  • --country — Country (any format)
  • --name (required) — Company name
  • --product — Product or industry hint
  • example: company --name "<company-name>"
  • example: company --company "<company-name>" --address <city>

eximagent company-memory get

Pull the latest outbound + inbound email exchange between the user and a company (PG email + sg_* events). Use with a company name or id to surface negotiation context (last quote subject, last reply snippet).

  • --companyId (required) — company UUID of the counterparty
  • example: company-memory get --companyId <company UUID>

eximagent company resolve

Knowledge-first company resolution: one cheap LLM call that returns the website it already knows (with confidence 0-2 + reason) and the entity splits — BEFORE any paid web-search/crawl. Call this first; escalate to enrich company only when escalate=true (confidence<2 or a split).

  • --country — Known country, for disambiguation
  • --name (required) — Company name (may be a packed multi-entity cell)
  • --products — Known products/HS context, for disambiguation
  • example: eximagent company resolve --name "Avianca" --country CO

eximagent company shipments

Shipments where a company is exporter or importer

  • --limit — max rows (1-1000, default 100)
  • --name (required) — company name

eximagent company split

Decompose a packed trade-data company-name cell ('A // B', 'C/O', newline-joined) into its distinct legal entities — DBA/trade names stay as one entity. Use before company lookup / sanctions check / enrich when a name string may hold multiple companies.

  • --name (required) — The raw company-name cell to split
  • example: eximagent company split --name "L & S SHRINK SYSTEMS INC. // OXYGEN DEVELOPMENT"

eximagent company verify

Resolve a raw company name to its canonical website/domain — the canonical company identity that collapses name variants. Triage-first (cheap); escalates to a website-verification agent (crawl + reasoning) only when triage is weak. Cached, so repeat verification is free.

  • --name (required) — Raw company name to verify
  • example: eximagent company verify --name "Avianca"

eximagent contacts add

Manually add a contact (employee) tied to a company. Accepts either an existing companyId OR a companyUrl (auto-upserts into companies on the fly). Source tagged as 'manual'.

  • --companyId — company UUID. EITHER this OR companyUrl required.
  • --companyName — Display name (used when upserting from companyUrl).
  • --companyUrl — Company canonical URL (e.g. https://<company-domain>). Triggers upsert into companies. EITHER this OR companyId required.
  • --department — Department
  • --linkedinUrl — LinkedIn URL
  • --location — Location
  • --mail (required) — Email address
  • --name — Full name
  • --phone — Phone
  • --title — Job title
  • example: contacts add --companyUrl https://<company-domain> --companyName '<Company Name>' --mail name@<company-domain> --name '<Full Name>' --title 'Procurement Manager'
  • example: contacts add --companyId <id> --mail name@<company-domain> --title 'CPO'

eximagent corridor get

Get a saved trade corridor by name. Returns the full corridor record (exporter, importer, HS code, defaults, tariff snapshot if any). Run corridor list first to find the name.

  • --name (required) — Corridor name or id (e.g. fr-de-widgets). Discover via corridor list.
  • example: corridor get --name fr-de-widgets

eximagent corridor list

List saved trade corridors (most recent first). (no args)

  • example: corridor list

eximagent corridor remove

Remove a saved corridor by name.

  • --name (required) — Corridor name to remove
  • example: corridor remove --name <corridor-name>

eximagent corridor save

Save a trade lane (exporter × importer × HS code) as a reusable corridor, referenced later by its name or id and (when starred) surfaced as an empty-chat starter chip.

  • --defaultCurrency — ISO 4217 currency (e.g. 'USD')
  • --defaultIncoterm — Default Incoterm (e.g. 'FOB', 'CIF')
  • --exporterCountry (required) — Exporter country — accepts country name, ISO2, ISO3
  • --hsCode — HS code for this corridor (optional — anchor later via update)
  • --importerCountry (required) — Importer country — accepts country name, ISO2, ISO3
  • --name (required) — Corridor name or id (kebab-case, e.g. fr-de-widgets)
  • --star — Star this corridor (surfaces as starter chip)
  • example: corridor save --name fr-de-widgets --exporter-country France --importer-country Germany --hs-code 854430 --default-incoterm FOB --default-currency EUR --star true

eximagent corridor yield

Deliverable-contact yield SLO per corridor class (market × goods): deliverable contacts per enriched company, flagging every class below target so low-yield lanes surface as a measured class, not an anecdote. (no args)

  • example: corridor yield

eximagent country resolve

Resolve a country by name/ISO2/ISO3

  • --query (required) — Country identifier: name, ISO2, or ISO3
  • example: country resolve USA
  • example: country resolve --query "Viet Nam"
  • example: country resolve VN

eximagent crawl run

Fetch raw markdown content for a website. Returns the homepage plus a small set of structurally-relevant internal pages. Reuses the same crawl cache the search pipeline uses, so repeat asks within 100 days are free. For batch crawls use the bulk shape: eximagent --inputs urls.ndjson exim crawl run where each row is {"url": "https://..."} — one tool call, N parallel crawls, one streamed result.

  • --url (required) — Website URL to crawl (https://...). Returns the homepage plus a small set of internal pages (about/contact/products if discovered). Cache-aware: 100-day TTL keyed by canonical URL.
  • example: crawl run --url https://example.com
  • example: eximagent --inputs sites.ndjson exim crawl run # bulk shape

eximagent duty exposure

Trade-remedy and tariff profile for an HS/origin: effective rate, remedies, protection level

  • --dest — destination/market country (ISO 2) (the importing country)
  • --from — earliest month (YYYY-MM)
  • --hs6 — HS code (6-digit) to scope the market
  • --limit — max rows (1-1000, default 100)
  • --origin — origin country (ISO 2) (the sourcing country) filter
  • --source — dataset source filter
  • --to — latest month (YYYY-MM)

eximagent duty fta

FTA utilization for a market: preference used vs full-duty paid, un-utilized FTA by agreement

  • --dest — destination/market country (ISO 2) (the importing country)
  • --from — earliest month (YYYY-MM)
  • --hs6 — HS code (6-digit) to scope the market
  • --limit — max rows (1-1000, default 100)
  • --origin — origin country (ISO 2) (the sourcing country) filter
  • --source — dataset source filter
  • --to — latest month (YYYY-MM)

eximagent email cancel

Cancel an in-flight email send for a collection. Pipeline checks the cancel flag between drafts; partial sends already flushed cannot be unsent.

  • --collectionId (required) — Collection whose in-flight send should be cancelled
  • example: email cancel --collection-id <cid>

eximagent email draft

Draft personalized outbound emails per recipient WITHOUT sending (preview-only). Renders ConfirmSendCard with countdown; on user confirm the agent flushes the same drafts via email send --confirm with the same collectionId + brief + sender args.

  • --brief (required) — Outreach brief — what to mention, tone, ask
  • --ccMe — CC the sender on each outbound
  • --collectionId (required) — UUID of the collection to draft for
  • --profile — Saved ideal-profile name; when set, each draft references the observed fit (matched attributes) to personalize the opening
  • --senderEmail (required) — From email (rendered into drafts)
  • --senderName (required) — Sender display name
  • --trackingEnabled — Enable open/click tracking on the eventual send
  • example: email draft --collectionId <id> --brief 'angle for outreach; soft ask' --senderEmail you@x.com --senderName 'Your Name'

eximagent email followup

Schedule a non-responder follow-up. Wraps monitor.create with signal='non-responder-followup'; on fire, agent assembles drafts + ConfirmSendCard before flushing.

  • --after (required) — Wait window before firing (cron or 'every Xd' / 'every Xh')
  • --brief (required) — Follow-up brief (what to add in the second touch)
  • --campaignId (required) — Source campaign / collection id
  • --name (required) — Follow-up name or id
  • example: email followup --campaign-id js7abc --name dach-q2-followup --after 'every 5d' --brief 'gentle nudge with case-study link'

eximagent email history

List sent emails with delivery + engagement counts (delivered / opened / clicked / bounced).

  • --collectionId — Filter by collection ID
  • --limit — Max rows (default 50)
  • example: email history
  • example: email history --collectionId <id>

eximagent email send

Draft personalized outbound emails per recipient (profile-aware) and send. PREVIEW BY DEFAULT — without --confirm it only drafts and returns a preview, never sends. Pass --confirm to flush; the pre-send sanity guard (signature/sender-email/OFAC) runs first and refuses on any failed check. Writes the sent record on send.

  • --brief (required) — Outreach brief — what to mention, tone, ask
  • --ccMe — CC the sender on each outbound
  • --collectionId (required) — UUID of the collection to email
  • --confirm — Required to actually flush emails. WITHOUT --confirm this is always a safe preview (no send), even without --dryRun. The pre-send sanity guard runs only when --confirm is set.
  • --dryRun — Explicit preview alias. Equivalent to omitting --confirm — generates drafts without sending.
  • --includeLowConfidence — Include low-confidence recipient emails (role aliases info@/sales@, no-reply, single-letter local, image-filename addresses). Default false — these are auto-pruned and counted in stats.autoPruned.
  • --profile — Saved ideal-profile name; when set, each draft references the observed fit (matched attributes) to personalize the opening
  • --regenerate — Redraft fresh copy on send instead of flushing the exact drafts produced by the last email draft preview. Default false — send flushes the approved preview so sent copy matches what was reviewed.
  • --senderEmail (required) — From email (must be operator-owned domain)
  • --senderName (required) — Sender display name
  • --trackingEnabled — Enable open/click tracking
  • example: email send --collectionId <id> --brief 'angle; soft ask' --senderEmail you@x.com --senderName 'Your Name' # preview
  • example: email send --collectionId <id> --brief 'angle; soft ask' --senderEmail you@x.com --senderName 'Your Name' --confirm # flush after guard

eximagent employees filter

Filter persisted contacts of a collection by title / department / verification confidence. Pure in-memory filter over the collection rows that enrich contacts already persisted — never re-discovers, never billable. Recall-first doctrine: discover unfiltered, narrow after.

  • --collectionId (required) — UUID of the target collection
  • --confidence enum: extracted|verified — Keep only rows of this verification confidence
  • --departments — Comma-separated departments to keep (case-insensitive)
  • --titles — Comma-separated job-title substrings to keep (case-insensitive)
  • example: employees filter --collectionId js7abc... --departments procurement
  • example: employees filter --collectionId js7abc... --titles "procurement manager,buyer" --confidence verified

eximagent employees rank

Rank persisted contacts of a collection by one of three criteria: verified-first (deliverability confidence), seniority (title words like director/VP/head), or engagement-likelihood (upstream likely-to-engage flag). Pure in-memory ranking over already-persisted rows; never re-discovers, never billable.

  • --by (required) enum: engagement-likelihood|seniority|verified-first — Ranking criterion: by deliverability confidence, by seniority words in title, or by likely-to-engage flag.
  • --collectionId (required) — UUID of the target collection
  • --limit — Max ranked rows to return (top N).
  • example: employees rank --collectionId js7abc... --by seniority
  • example: employees rank --collectionId js7abc... --by verified-first --limit 10

eximagent enrich company

Structured company profile from the website itself. Crawls homepage + a few internal pages and runs a fast model on raw content to extract: description, industries, selling products (with HS codes), buying products (with HS codes), certificates, expos attended, international trade markers, nearest port, branches, trade potential 0-100. Also regex-extracts contact mails + phones from the crawled markdown (with noise filtering). Two input modes: (a) --url when you have the canonical site; (b) --company when you only have the name — we search the web and either run on the single plausible site OR return a candidates list. Cache-aware (100d).

  • --compact — Return a slim profile (drop images, evidence snippets, store list, product descriptions) — the core website/products/contacts/trade fields only, for agents that need a compact result.
  • --company — Company name — we resolve a likely website via web search. Ambiguous names return a candidates list to disambiguate (ask the user to pick, then re-run with --url).
  • --strict — When set, ambiguous --company names return a blocking candidates list instead of auto-picking the top match. Single-input only; bulk runs always auto-pick.
  • --url — Company website URL (https://...). Validated for reachability + that the host is a real business site (not a blog / news / social / aggregator).
  • exactly one of: --company / --url
  • example: enrich company --url https://<company-domain>
  • example: enrich company --company "<company name>"

eximagent enrich contact

Re-verify a single employee email via the contact verification provider; fills mail when found.

  • --employeeId (required) — Employee ID whose email to re-verify
  • example: enrich contact --employeeId <id>

eximagent enrich contacts

Enrich a collection (or a row subset of one) with decision-maker contacts. Upstream people-search + verified-email enrichment. Subset filters: --priority (high/medium/low only), --limit N (top N after filter), --row-ids (explicit collectionItem ids), --only-with-website (skip companies without canonical site), --max-cost-cents (hard budget cap; loop stops at threshold). Confidence model on emitted contacts: verified-source → confidence=verified (deliverable email); probable-source → confidence=extracted (probable email shape). Agents should state verified emails as fact; extracted as candidate data.

  • --collectionId (required) — UUID of the target collection
  • --departments — Comma-separated departments (e.g. procurement,purchasing)
  • --limit — Max collection rows to enrich (after --priority / --row-ids filters). Bills only the selected rows.
  • --maxCostCents — Hard cost cap in cents. Loop stops once accumulated approximate cost meets this budget.
  • --onlyWithWebsite — Skip rows whose company has no canonical website (saves contact-enrich spend on un-crawlable orgs).
  • --priority enum: high|low|medium — Filter to rows of this priority only before enriching.
  • --rowIds — Comma-separated collectionItem Ids — enrich only this explicit subset.
  • --seniorities — Comma-separated seniorities (e.g. director,head,manager)
  • --titles — Comma-separated job titles
  • example: enrich contacts --collectionId js7abc... --titles 'procurement manager,buyer'
  • example: enrich contacts --collectionId js7abc... --priority high --limit 25
  • example: enrich contacts --collectionId js7abc... --row-ids id1,id2,id3 --max-cost-cents 500

eximagent evidence show

Show raw evidence for one shipment (source provenance)

  • --id (required) — shipment id
  • --normalized — also include English-normalized evidence fields

eximagent hscode search

Search HS codes; cascades lexical -> hybrid (embedding) -> llm-expanded as result quality demands.

  • --level enum: section|chapter|heading|subheading — Restrict to one hierarchy level
  • --limit — Max results (1-50, default 5)
  • --query (required) — HS code (digits) or product keyword
  • example: hscode search --query "frozen shrimp"
  • example: hscode search --query <product> --level chapter
  • example: hscode search --query 0201 # by code prefix

eximagent ideal-profile delete

Delete a saved ideal customer profile.

  • --name (required) — Profile name

eximagent ideal-profile get

Get a saved ideal customer profile.

  • --name (required) — Profile name

eximagent ideal-profile list

List saved ideal customer profiles. (no args)

eximagent ideal-profile save

Save or update an ideal customer profile with optional custom weights.

  • --name (required) — Profile name
  • --profile — IdealProfileView JSON
  • --weights — Dimension weights JSON

eximagent kb add

Register a knowledge-base entry. Accepts either (a) uploaded file via --fileId (from kb upload-url flow), OR (b) text content via --content (no upload needed). Content gets injected into email-gen + profile-extract context.

  • --businessType enum: export|import — Trade direction
  • --content — Extracted text content (for LLM retrieval)
  • --fileId — storage ID (from kb upload-url flow). Optional when content is provided text-only.
  • --fileSize — Bytes
  • --fileType — MIME type
  • --filename (required) — Display filename
  • --tags — Comma-separated tags
  • example: kb add --fileId <id> --filename pricing.pdf --tags 'pricing,sales'
  • example: kb add --filename pricing-notes.txt --content 'Our Q2 pricing tier: ...' --tags 'pricing'

eximagent kb get

Get a knowledge-base entry by filename. Returns the full record including tags + metadata + (truncated) content. For a quick excerpt only, use kb preview.

  • --filename (required) — Filename of the KB entry. Discover via kb list.
  • example: kb get --filename brochure.pdf

eximagent kb list

List user knowledge-base entries. (no args)

  • example: kb list

eximagent kb preview

Preview a knowledge-base file: returns a content excerpt + classification (B/L / COO / invoice / etc.) + tags so user can verify content without downloading.

  • --kbId (required) — KB entry id
  • example: kb preview --kb-id <id>

eximagent kb remove

Delete a knowledge-base entry by ID.

  • --id (required) — KB entry ID
  • example: kb remove --id <kbId>

eximagent landed cost

Landed-cost breakdown for an HS/market: FOB, freight, insurance, duties, per-kg and over-FOB

  • --dest — destination/market country (ISO 2) (the importing country)
  • --from — earliest month (YYYY-MM)
  • --hs6 — HS code (6-digit) to scope the market
  • --limit — max rows (1-1000, default 100)
  • --origin — origin country (ISO 2) (the sourcing country) filter
  • --source — dataset source filter
  • --to — latest month (YYYY-MM)

eximagent linkedin lookup

LinkedIn company page batch lookup. Accepts canonical LinkedIn URLs via --urls AND/OR company names or website URLs via --queries — names/URLs auto-resolve to canonical LinkedIn pages via web search before scrape. Cached 100 days per resolved URL. Returns structured profile data keyed by resolved URL plus a resolutions report so the agent can audit which queries mapped to which URL.

  • --queries — Comma-separated company names OR website URLs OR LinkedIn URLs. Each input is auto-resolved to a canonical linkedin.com/company URL via web search before scraping. Mix freely with --urls; both feed the same batch.
  • --urls — Comma-separated LinkedIn company URLs (canonical, e.g. https://linkedin.com/company/<slug>)
  • example: linkedin lookup --urls "https://linkedin.com/company/<slug-a>,https://linkedin.com/company/<slug-b>"
  • example: linkedin lookup --queries "<Company A>,<Company B>"
  • example: linkedin lookup --queries "https://company-a.example.com,https://company-b.example.com"

eximagent market anomalies

Trend-relative anomalies for an HS6 market: price-shock and volume-spike periods vs the market's own baseline

  • --bucket enum: month|quarter — time bucket: month|quarter (def month)
  • --dest (required) — destination country (ISO 2) — the market whose movement to read (required)
  • --from — earliest month (YYYY-MM)
  • --hs6 (required) — HS code (6-digit) for the traded market (required)
  • --origin — origin country (ISO 2) filter (narrow to one supplier country)
  • --source — dataset source filter
  • --to — latest month (YYYY-MM)

eximagent market churned

Lapsed importers: active before --since, gone after

  • --country — reporting country (ISO 2) to scope the directory
  • --hs6 — HS code (6-digit) to scope the market
  • --limit — max rows (1-1000, default 100)
  • --since — lookback months (def 12)

eximagent market compare

Compare one HS6 across destinations side by side: value, price/kg, growth, top buyer — the cross-country arbitrage and sizing view

  • --dests (required) — comma-separated destination ISO2 list to compare the HS across
  • --hs6 (required) — HS code (6-digit) for the traded market (required)

eximagent market entrants

New importers in a market (country×HS6), no history before --since

  • --country — reporting country (ISO 2) to scope the directory
  • --hs6 — HS code (6-digit) to scope the market
  • --limit — max rows (1-1000, default 100)
  • --since — lookback months (def 12)

eximagent market growth

Growing importers: recent value over prior by --min_growth

  • --country — reporting country (ISO 2) to scope the directory
  • --hs6 — HS code (6-digit) to scope the market
  • --limit — max rows (1-1000, default 100)
  • --minGrowth — min growth ratio (def 0.25)
  • --since — lookback months (def 12)

eximagent market momentum

Rank a destination's HS6 markets by recent-vs-prior growth — the emerging and declining surfaces

  • --dest (required) — destination country (ISO 2) to scan for hot/cooling HS6 markets (required)
  • --hs2 — HS2 chapter to narrow the scan (optional)
  • --limit — max rows (1-1000, default 100)
  • --source — dataset source filter

eximagent market trend

Market time-series for an HS6 into a destination: value, buyers, price, MoM/YoY growth, momentum and a rising/falling/flat verdict

  • --bucket enum: month|quarter — time bucket: month|quarter (def month)
  • --dest (required) — destination country (ISO 2) — the market whose movement to read (required)
  • --from — earliest month (YYYY-MM)
  • --hs6 (required) — HS code (6-digit) for the traded market (required)
  • --origin — origin country (ISO 2) filter (narrow to one supplier country)
  • --source — dataset source filter
  • --to — latest month (YYYY-MM)

eximagent monitor cancel

Cancel (disable) a monitor by name.

  • --name (required) — Monitor name to cancel
  • example: monitor cancel --name germany-replies

eximagent monitor create

Create a recurring SIGNAL-BASED monitor that fires on trade-domain events (reply arrived, non-responder follow-up, new company matching criteria, tariff change, dead domain). NOT for date-based reminders — use reminder create for those.

  • --description (required) — What this monitor watches
  • --enrollSequenceId — For new-match watches: sequence UUID to auto-enroll each new strong-fit company into (trade-signal-triggered outreach)
  • --name (required) — Monitor name or id
  • --schedule (required) — Schedule: hourly|daily|weekly or 'every <N>m|h|d|w' (e.g. 'every 6h')
  • --signal (required) enum: reply-arrived|non-responder-followup|new-company-matching-criteria|tariff-change|dead-domain — Signal kind to watch
  • --target (required) — Target identifier (collectionId, criteria JSON, etc.)
  • example: monitor create --name reply-watch --signal reply-arrived --target campaign-123 --schedule 'every 1h' --description 'Watch for inbound reply'

eximagent monitor get

Get a saved monitor by name. Returns the full record (signal, target, schedule, enabled). Run monitor list first if you need to discover the name.

  • --name (required) — Monitor name. Discover via monitor list.
  • example: monitor get --name <monitor-name>

eximagent monitor list

List user SIGNAL-BASED monitors (enabled by default). Monitors are recurring, fire on trade events (reply-arrived, tariff-change, etc.). NOT the same as reminder list (one-shot date-based). When user asks broadly "what watches/alerts do I have", call this AND reminder list to surface both.

  • --includeDisabled — Include disabled monitors (default false)
  • example: monitor list

eximagent pipeline stop

Cancel a running search and clear busy state. With --runId, cancels that specific run; without it, cancels the user's in-flight run. Marks the run as cancelled. Idempotent — no-op when nothing is running.

  • --runId — Optional run id to cancel a specific run; defaults to your in-flight run.
  • example: pipeline stop
  • example: pipeline stop --runId run_abc123

eximagent policy get

Show the current outreach policy. (no args)

eximagent policy history

List every saved outreach-policy version (audit trail). (no args)

eximagent policy set

Set the outreach policy that grounds reply drafting: approved facts, rules (e.g. price_floor), and guardrails (blocked_terms, require_nda_before_coa). Each save bumps the version.

  • --facts — JSON object of approved facts the AI may state
  • --guardrails — JSON guardrails, e.g. {"blockedTerms":["guarantee"],"unavailableCerts":["HALAL"],"tone":"warm, concise","requireNdaBeforeCoa":true,"requireSignature":true,"autoSendSafe":false}
  • --rules — JSON rules, e.g. {"priceFloor":10,"signature":"— Phuc, EximAgent"}
  • example: eximagent policy set --rules '{"priceFloor":10}'

eximagent price shipments

Shipments for an HS code above a weight threshold

  • --hsCode (required) — HS code (4/6/8/10 digit prefix)
  • --limit — max rows (1-1000, default 100)
  • --minWeightKg — min gross weight kg

eximagent product shipments

Shipments matching an HS code prefix

  • --hsCode (required) — HS code (4/6/8/10 digit prefix)
  • --limit — max rows (1-1000, default 100)

eximagent products add

Save or update a product in the user profile. Image uploaded via products upload-url flow.

  • --businessType enum: export|import — Trade direction
  • --category — Category
  • --description — Short product description
  • --hsCode — HS code
  • --imageId — storage ID for product image (from upload-url flow)
  • --moq — Minimum order quantity (e.g. "5 tons")
  • --name (required) — Product name or id
  • example: products add --name 'premium widget A' --moq '5 tons' --description 'industrial grade, custom spec'

eximagent products get

Get a saved user product by name. Returns the full product record (description, HS code, MOQ, category, image). Run products list first to discover the name.

  • --name (required) — Product name or id. Discover via products list.
  • example: products get --name premium-widget-a

eximagent products list

List user products.

  • --businessType enum: export|import — Filter
  • example: products list
  • example: products list --businessType export

eximagent products remove

Remove a product from the user profile.

  • --name (required) — Product name to remove
  • example: products remove --name premium-widget-a

eximagent profile-match analyze

Extract an ideal-customer profile from one or more reference companies (url/name/text, positive or negative) and save it for ranking.

  • --apply — Save the profile (default true); set false to preview only
  • --collectionId — Learn the profile from an existing collection — every member becomes a positive reference ("find more like my best accounts")
  • --name — Name to save the ideal profile under
  • --references — JSON array of references: [{"type":"url|text","value":"...","polarity":"positive|negative"}]
  • --url — A single reference company website
  • example: eximagent profile-match analyze --url https://acme-importer.com --name specialty-coffee

eximagent profile-match lookalike

Find companies that trade like a seed company — same products and source markets derived from real shipment behavior in the corpus, ranked by trade-axis fit.

  • --limit — Maximum number of lookalikes to return
  • --name (required) — Seed company name to find trade-axis lookalikes for
  • --role — Trade role to match on: importer (default) or exporter
  • example: eximagent profile-match lookalike --name "Acme Coffee Importers" --role importer

eximagent profile-match rank

Rank the companies in a collection by fit against a saved ideal profile, with explained scores.

  • --collectionId (required) — Collection of candidate companies to rank
  • --name (required) — Saved ideal profile name
  • example: eximagent profile-match rank --collection_id <id> --name specialty-coffee

eximagent profile-match score

Fit-rank ANY list of companies against a saved ideal profile — the general fit primitive: pipe in search results, an enrichment batch, or any hand-built list; each gets an explained fit score + band + matched/missing attributes. Fit is a lens for every surface.

  • --companies (required) — Companies to score: JSON [{"name":"...","website":"..."}]
  • --name — Saved ideal profile name (or pass --references)
  • --references — Inline references JSON if no saved profile
  • example: eximagent profile-match score --name specialty-coffee --companies '[{"name":"Acme Coffee","website":"acme.com"}]'

eximagent profile-match search

Search the company corpus and rank hits by fit to a saved ideal profile or inline references — fit-ranking without a pre-built collection.

  • --country — Country term to seed the corpus search
  • --market — Target market to retarget a proven profile to a new geography (cross-market expansion) — overrides the profile's countries for retrieval + scoring
  • --name — Saved ideal profile name (or pass --references instead)
  • --product — Product term to seed the corpus search
  • --query — Search query (defaults to the profile summary)
  • --references — Inline references JSON if no saved profile
  • example: eximagent profile-match search --name specialty-coffee --product coffee

eximagent profile-match watch

Turn a saved ideal profile into a self-growing watchlist — a scheduled agent that keeps finding new strong-fit companies and accumulates them in a 'watch:' collection.

  • --name (required) — Saved ideal profile name to watch
  • --schedule — How often to hunt: hourly|daily|weekly or 'every <N>m|h|d|w' (default daily)
  • example: eximagent profile-match watch --name specialty-coffee --schedule daily

eximagent profile extract

Extract user-profile fields (company, products, markets, role, language, contacts) from text utterance OR URL crawl OR file content. Default behavior: persists extracted fields to the profile (apply=true). Pass --apply false to preview the extraction without writing.

  • --apply — Persist extracted fields to the profile via profile.update (default true). Pass false to preview only.
  • --content — Plain-text file content (when from='file')
  • --filename — File name for context (when from='file')
  • --from (required) enum: text|url|file — Source kind: 'text' = extract from utterance; 'url' = crawl website then extract; 'file' = use provided text content
  • --url — Company website URL (when from='url')
  • --utterance — Free-text user utterance (when from='text')
  • example: profile extract --from text --utterance "I export industrial fans from France"
  • example: profile extract --from url --url https://example.com
  • example: profile extract --from file --filename brochure.pdf --content "..."

eximagent profile get

Read the user's business profile. (no args)

  • example: profile get

eximagent profile reset

Reset the current user profile to empty. Irreversible. Use when the user explicitly asks to "start fresh" / "clear my profile" / "reset". Other artifacts (collections, corridors, templates, etc.) are not touched — remove those with their own remove verbs. (no args)

  • example: profile reset

eximagent profile update

Update fields on the user's business profile. Omitted fields are preserved.

  • --company — Company name
  • --companyDescription — Brief company description
  • --companyLinkedin — Company LinkedIn URL
  • --description — Free-text user description
  • --industries — Comma-separated industries
  • --job — Job title
  • --note — Internal note
  • --preferredLanguage — Preferred language code (e.g. en, vi)
  • --role — Role description
  • --signature — Email signature
  • --sources — Comma-separated sourcing countries
  • --targets — Comma-separated target market countries
  • --userLinkedin — User LinkedIn URL
  • --websites — Comma-separated company / personal websites
  • example: profile update --signature 'Best, <name> / <company>'
  • example: profile update --industries "<industry>" --targets "<country>,<country>"

eximagent prospects find

Compound lead query: growing importers of an HS6 in a market who buy from a non- supplier, have a deliverable email, and are not already in a collection

  • --excludeCollection — drop importers already in this collection (the not-my-customer filter)
  • --growing — only importers whose recent value beats prior by --min_growth
  • --hasEmail — only importers the corpus can supply a deliverable email for
  • --hs6 (required) — HS code (6-digit) to scope the market
  • --limit — max rows (1-1000, default 100)
  • --market — destination market (ISO2) the importers ship into
  • --minGrowth — min growth ratio (def 0.25)
  • --since — lookback months (def 12)
  • --supplierNot — exclude importers whose top supplier originates in this ISO2
  • example: eximagent prospects find --hs6 090111 --market us --growing --supplier_not br --has_email

eximagent reminder cancel

Cancel a pending reminder by name.

  • --name (required) — Reminder name to cancel
  • example: reminder cancel --name <reminder-name>

eximagent reminder create

Create a one-shot DATE-BASED reminder that fires at a specific ISO timestamp (e.g. "remind me Monday 9am to review the German campaign"). NOT for recurring or signal-based watches — for those use monitor create. Use reminder list to see saved reminders.

  • --description (required) — What to remember
  • --name (required) — Reminder name or id
  • --tz — IANA timezone (e.g. Asia/Bangkok) for whenIso when it carries no offset
  • --whenIso (required) — When to fire (ISO 8601, e.g. 2026-05-15T10:00:00Z)
  • example: reminder create --name <reminder-name> --whenIso 2026-05-15T10:00:00Z --description 'Check reply received'

eximagent reminder get

Get a saved reminder by name. Returns the full record (description, fireAt, fired). Run reminder list first to discover the name.

  • --name (required) — Reminder name. Discover via reminder list.
  • example: reminder get --name <reminder-name>

eximagent reminder list

List user DATE-BASED reminders (pending by default). Reminders are one-shot, fire at a specific ISO timestamp. NOT the same as monitor list (recurring trade-signal watches — replies, tariff changes, etc.). When user asks "what reminders do I have", call this AND monitor list to surface both.

  • --includeFired — Include fired reminders (default false)
  • example: reminder list
  • example: reminder list --includeFired true

eximagent reply approve

Send an AI-drafted reply after review. Preview by default; --confirm sends. A suppression check runs first and refuses on a suppressed recipient.

  • --confirm — Required to actually send. Without it this is a safe preview.
  • --reviewId (required) — Reply review UUID
  • example: eximagent reply approve --reviewId <id> --confirm

eximagent reply edit

Edit an AI-drafted reply's subject/body before approving; keeps it pending.

  • --body — New body (optional)
  • --reviewId (required) — Reply review UUID
  • --subject — New subject (optional)

eximagent reply list

List AI-drafted replies awaiting human review. Replies are grounded in the outreach policy and validated against its guardrails; any violation or handoff signal routes to review. (no args)

eximagent reply reject

Reject an AI-drafted reply; nothing is sent.

  • --reviewId (required) — Reply review UUID

eximagent reply request-rewrite

Ask the AI to redraft a reply, optionally with reviewer guidance; result stays pending.

  • --guidance — Optional guidance steering the rewrite
  • --reviewId (required) — Reply review UUID

eximagent reply show

Surface the most-recent inbound reply for the user (or scoped to a collection). Returns {fromEmail, subject, snippet, summary, receivedAt}. Populated by the inbound-mail webhook.

  • --collectionId — Filter to one collection (optional)
  • example: reply show
  • example: reply show --collection-id <cid>

eximagent route shipments

Shipments on an origin→destination country route

  • --dest (required) — Destination country (ISO 2)
  • --limit — max rows (1-1000, default 100)
  • --origin (required) — Origin country (ISO 2)

eximagent run cancel

Cancel an in-flight async run, keyed by --runId OR --collectionId, and release its idempotency slot so a fresh run can start. Marks the run terminal (status=cancelled) and refunds the reserved estimate so cancelled work is never billed. No-op-safe: cancelling a run that is already terminal returns NOT_FOUND. After cancel use run retry to re-run cleanly.

  • --collectionId — Collection UUID; cancels its running run.
  • --runId — Run UUID to cancel.
  • exactly one of: --runId / --collectionId
  • example: run cancel --collectionId 1f2...
  • example: run cancel --runId 9b3...

eximagent run retry

Re-run a collection's discovery with a fresh idempotency slot after a previous run finished, failed, stalled, or was cancelled. Cancels any still-running run first (refunding its reserve), then kicks off a new run over the same saved criteria. Pass --newIdempotencyKey to label the retry; the server always allocates a fresh run id so paid work is never duplicated.

  • --collectionId (required) — Collection UUID whose discovery to re-run.
  • --newIdempotencyKey — Optional label for the retry; a fresh run id is always allocated.
  • example: run retry --collectionId 1f2... --newIdempotencyKey retry-1

eximagent run status

Current snapshot of an async run, keyed by --runId OR --collectionId. Works on in-flight runs (status=running with partial counts), finished runs (status=completed/cancelled/failed), and stalled runs (status=stalled when the heartbeat has gone silent past the stall threshold). Returns the parent collection name, start/end timestamps, companies processed/expected, percentComplete, reserved/charged/refunded cents, canRetry + retryAfterSeconds, and the priority breakdown when available. This is the same envelope a duplicate Idempotency-Key returns and the /status route emits.

  • --collectionId — Collection UUID; resolves the latest run for that collection.
  • --runId — Run UUID returned by exim search run --confirmed true.
  • exactly one of: --runId / --collectionId
  • example: run status --runId 9b3...
  • example: run status --collectionId 1f2...

eximagent run summary

Per-run summary card after a search pipeline finishes (or while it is still running). Returns criteria + query + start/finish timestamps + duration + total companies + priority breakdown + model used + status. For the live snapshot of an in-flight run use exim run status; this command is the post-mortem view that prints the full criteria back so the agent can re-run with the same shape.

  • --runId (required) — Run UUID; finished runs preferred.
  • example: run summary --runId 9b3...

eximagent sanctions check

Screen a name against the OFAC SDN sanctions list (Specially Designated Nationals). Returns matches with program (e.g. SDGT/IRAN/CUBA) and aliases. Substring + alias match. Always advisory — final clearance lives with the founder/legal.

  • --name (required) — Company or person name to screen against OFAC SDN list
  • example: sanctions check --name "<entity-name>"

eximagent search refine

Preview an additive/subtractive refinement of an existing collection's criteria. Returns a diff card (kind: 'refine-preview') showing which filters add/remove + expected company-count delta. After user confirms, caller should invoke exim search run --confirmed=true with merged criteria.

  • --addExcludeBusinessType — Add to exclude business types (CSV)
  • --addExcludeLocation — Add to exclude locations (CSV)
  • --addIndustry — Add industry filter
  • --addLocation — Add target market(s) — CSV: Austria,Switzerland
  • --collectionId (required) — collection UUID to refine
  • --removeExcludeBusinessType — Remove exclude business types (CSV)
  • --removeExcludeLocation — Remove exclude locations (CSV)
  • --removeIndustry — Drop industry filter entirely
  • --removeLocation — Remove target market(s) — CSV
  • example: search refine --collection-id <cid> --add-location "Austria,Switzerland"
  • example: search refine --collection-id <cid> --remove-industry --add-exclude-business-type "retail"

eximagent search run

Autonomous buyer/importer discovery. Finds candidate companies, reviews and scores each, ranks top-K, and saves them to a Collection. Preview is mandatory — first call (confirmed=false) returns a criteria preview; user confirms → second call (confirmed=true) starts the non-blocking run. Emits progress events to the run.

  • --category enum: export|import — Trade direction: export (you sell, we find buyers) or import (you buy, we find sellers).
  • --confirmed — When true, kicks the pipeline. When false (default), returns a criteria-preview card with a previewToken for user confirmation.
  • --direction enum: buyers|sellers — Agent-friendly synonym for --category. "buyers" → export (you sell); "sellers" → import (you buy). Mutually exclusive with --category; if both pass, --direction wins for preview text.
  • --excludeBusinessType — Exclude business types
  • --excludeLocation — Exclude locations
  • --hsCode — HS code (anchors the corridor + tariff context; agent should disambiguate via exim hscode search before kickoff)
  • --industry — Industry
  • --location — Target market country — accepts country name, ISO2, ISO3 (e.g. "Germany", "DE", "DEU")
  • --name — Collection name (auto-slug if omitted)
  • --previewToken — Echo back the previewToken from the prior --confirmed=false preview to bind the kickoff to identical args. Server rejects if args drift from what was previewed.
  • --product (required) — Product to find buyers/sellers for
  • --targetBusinessDescription — Target buyer/seller profile
  • example: search run --product "<product>" --location Germany --category import
  • example: search run --confirmed true --product "<product>" --location Germany --hs-code 090111

eximagent sequence create

Create a multi-step email sequence (cadenced follow-ups). Steps is a JSON array of {waitDays,subject,body}; templates support {first_name},{company},{sender_name},{signature}.

  • --name (required) — Sequence name
  • --senderEmail (required) — From email (operator-owned, verified)
  • --senderName (required) — Sender display name
  • --signature — Signature appended via {signature} in templates
  • --steps (required) — JSON array of steps {waitDays,subject,body,variants?:[{subject,body}]}; variants A/B auto-converge to the best by click-rate
  • example: eximagent sequence create --name X --senderEmail you@x.com --steps '[{"waitDays":0,"subject":"Hi"}]'

eximagent sequence from-brief

Draft a multi-step sequence from a natural-language brief (AI), saved as draft.

  • --brief (required) — Natural-language outreach brief
  • --name — Sequence name (defaults to an AI-suggested name)
  • --senderEmail (required) — From email (operator-owned, verified)
  • --senderName (required) — Sender display name
  • --signature — Signature appended via {signature}

eximagent sequence from-template

Create a new draft sequence from a saved template.

  • --name — New sequence name (defaults to the template name)
  • --senderEmail (required) — From email (operator-owned, verified)
  • --senderName (required) — Sender display name
  • --signature — Signature appended via {signature}
  • --templateName (required) — Template to instantiate

eximagent sequence list

List your email sequences and their status. (no args)

eximagent sequence metrics

Show a sequence's enrollment counts by status (enrolled/active/replied/completed/suppressed).

  • --sequenceId (required) — Sequence UUID

eximagent sequence pause

Pause an active sequence; no further steps send until resumed.

  • --sequenceId (required) — Sequence UUID

eximagent sequence start

Activate a sequence and enroll a collection's recipients. Preview by default; --confirm sends real emails on schedule. A reply from a recipient auto-stops their remaining follow-ups.

  • --collectionId (required) — Collection UUID to enroll
  • --confirm — Required to actually activate + enroll. Without it, this is a safe preview.
  • --sequenceId (required) — Sequence UUID
  • example: eximagent sequence start --sequenceId <id> --collectionId <id> --confirm

eximagent sequence template-from-trade

Generate a sequence template from a seed company's real customs trade pattern (AI), saved as a reusable trade-seeded template — outreach copy tuned to how companies like the seed actually trade.

  • --name (required) — Template name
  • --seedCompany (required) — Seed company whose corpus trade pattern seeds the template

eximagent sequence template-save

Save a reusable sequence template (named set of steps) for fast sequence creation.

  • --name (required) — Template name
  • --steps (required) — JSON array of steps {waitDays,subject,body,variants?:[{subject,body}]}; variants A/B auto-converge to the best by click-rate

eximagent sequence templates

List your saved sequence templates. (no args)

eximagent sequence validate

Check a sequence is launch-ready (sender set, steps present, policy configured).

  • --sequenceId (required) — Sequence UUID

eximagent shipments buyer-recurrence

Buyer recurrence cohort: repeat buyers, retention and shipment scale

  • --buyer — buyer company name filter
  • --dest — destination country (ISO 2) filter
  • --from — earliest month (YYYY-MM)
  • --hs6 — HS code (6-digit) to scope the market
  • --origin — origin country (ISO 2) filter
  • --source — dataset source filter
  • --to — latest month (YYYY-MM)
  • example: eximagent shipments buyer-recurrence --hs6 090111 --dest DE

eximagent shipments get

Get one shipment by deterministic id

  • --id (required) — shipment id
  • --view enum: summary|detail|logistics|financials|parties|evidence — field projection: summary|detail|logistics|financials|parties|evidence

eximagent shipments market-signals

Market-level demand, concentration and momentum signals for an HS or destination

  • --dest — destination country (ISO 2) filter
  • --from — earliest month (YYYY-MM)
  • --hs6 — HS code (6-digit) to scope the market
  • --origin — origin country (ISO 2) filter
  • --source — dataset source filter
  • --to — latest month (YYYY-MM)
  • example: eximagent shipments market-signals --hs6 090111 --dest DE

eximagent shipments price-trend

Monthly price-per-kg trend, dispersion and concentration shift

  • --dest — destination country (ISO 2) filter
  • --from — earliest month (YYYY-MM)
  • --hs6 — HS code (6-digit) to scope the market
  • --origin — origin country (ISO 2) filter
  • --source — dataset source filter
  • --to — latest month (YYYY-MM)
  • example: eximagent shipments price-trend --hs6 090111 --dest DE

eximagent shipments route-signals

Origin to destination route signals ranked by traded value

  • --dest — destination country (ISO 2) filter
  • --from — earliest month (YYYY-MM)
  • --hs6 — HS code (6-digit) to scope the market
  • --limit — max rows (1-1000, default 100)
  • --origin — origin country (ISO 2) filter
  • --source — dataset source filter
  • --to — latest month (YYYY-MM)
  • example: eximagent shipments route-signals --hs6 090111 --dest DE

eximagent shipments search

Search shipments across all dimensions

  • --dest — Destination country (ISO 2)
  • --hs6 — HS code (first 6 digits)
  • --hsCode — HS code (4/6/8/10 digit prefix)
  • --limit — max rows (1-1000, default 100)
  • --name — company name (case-insensitive substring)
  • --origin — Origin country (ISO 2)
  • example: eximagent shipments search --hs6 090111 --dest DE --limit 50
  • example: eximagent shipments search --name "Acme GmbH"

eximagent stats show

Conversational analytics on sent emails: reply-rate / open-rate / click-rate / bounce-rate computed from PG email + sg_* event tables. Optionally scope to a single collection.

  • --collectionId — Filter by collection id (optional)
  • --limit — Max emails to scan (default 1000)
  • example: stats show
  • example: stats show --collection-id <cid>
  • example: stats show --collection-id <cid> --limit 500

eximagent suppression add

Manually suppress an email from all outreach.

  • --email (required) — Email address to suppress

eximagent suppression list

List manually suppressed emails. (no args)

eximagent suppression remove

Remove a manual suppression.

  • --email (required) — Email address to un-suppress

eximagent tariff

Trade/tariff/duty for any corridor. --product optional (omit for corridor overview).

  • --exporter (required) — Sending country — accepts country name, ISO2, ISO3 (e.g. "Viet Nam", "VN", "VNM")
  • --importer (required) — Receiving country — accepts country name, ISO2, ISO3 (e.g. "Germany", "DE", "DEU")
  • --product — Product / goods description
  • example: tariff --exporter <iso> --importer <iso> --product <product>
  • example: tariff --from <country> --to <country> --goods <product>
  • example: tariff --exporter <iso> --importer <iso> # corridor overview, no product

eximagent template add

Save or update an email template. Variables (e.g. {{name}}, {{company}}) auto-extracted; attachment file-IDs auto-resolved.

  • --businessType enum: export|import — Trade direction this template targets
  • --category — Category (e.g. 'cold-outreach', 'follow-up', 'sales')
  • --content (required) — Template body. Supports {{variable}} placeholders + [FILE_ID:storageId:filename] attachment markers.
  • --name (required) — Template name or id
  • --subject (required) — Subject line (may use {{variables}})
  • example: template save --name cold-intro --subject 'Partnership intro' --content 'Hi {{name}}, ...'

eximagent template create

Save or update an email template. Variables (e.g. {{name}}, {{company}}) auto-extracted; attachment file-IDs auto-resolved.

  • --businessType enum: export|import — Trade direction this template targets
  • --category — Category (e.g. 'cold-outreach', 'follow-up', 'sales')
  • --content (required) — Template body. Supports {{variable}} placeholders + [FILE_ID:storageId:filename] attachment markers.
  • --name (required) — Template name or id
  • --subject (required) — Subject line (may use {{variables}})
  • example: template save --name cold-intro --subject 'Partnership intro' --content 'Hi {{name}}, ...'

eximagent template delete

Delete a saved email template by name. Irreversible. NOT for cancelling a draft batch — for that the draft layer has its own flow.

  • --name (required) — Template name to delete. Discover via template list.
  • example: template remove --name <template-name>

eximagent template edit

Update a saved template. Pass only fields to change; others stay.

  • --category — New category (replaces if provided)
  • --content — New body (replaces if provided; supports {{variables}} + [FILE_ID:...] markers)
  • --name (required) — Template name or id
  • --subject — New subject (replaces if provided; supports {{variables}})
  • example: template edit --name cold-intro --content 'Hi {{name}}, ...'

eximagent template generate

Generate an email template (subject + body with {{variables}}) from a free-text prompt. Caller saves via template save.

  • --prompt (required) — Prompt: tone + intent + product + audience (e.g. "casual cold outreach for B2B importers")
  • example: template generate --prompt 'casual cold-outreach for first contact, B2B importers'

eximagent template get

Read a saved template by name (full content + variables + attachments).

  • --name (required) — Template name or id
  • example: template recall --name cold-intro

eximagent template list

List the user saved email templates. (no args)

  • example: template list

eximagent template recall

Read a saved template by name (full content + variables + attachments).

  • --name (required) — Template name or id
  • example: template recall --name cold-intro

eximagent template remove

Delete a saved email template by name. Irreversible. NOT for cancelling a draft batch — for that the draft layer has its own flow.

  • --name (required) — Template name to delete. Discover via template list.
  • example: template remove --name <template-name>

eximagent template save

Save or update an email template. Variables (e.g. {{name}}, {{company}}) auto-extracted; attachment file-IDs auto-resolved.

  • --businessType enum: export|import — Trade direction this template targets
  • --category — Category (e.g. 'cold-outreach', 'follow-up', 'sales')
  • --content (required) — Template body. Supports {{variable}} placeholders + [FILE_ID:storageId:filename] attachment markers.
  • --name (required) — Template name or id
  • --subject (required) — Subject line (may use {{variables}})
  • example: template save --name cold-intro --subject 'Partnership intro' --content 'Hi {{name}}, ...'

eximagent trade lookup

Search trade data: tariffs, duties, remedies, NTM measures by importer/exporter/product.

  • --exporter (required) — Sending country — accepts country name, ISO2, ISO3 (e.g. "Viet Nam", "VN", "VNM")
  • --hsCode — HS code (2-10 digits, no separators)
  • --importer (required) — Receiving country — accepts country name, ISO2, ISO3 (e.g. "Germany", "DE", "DEU")
  • --limit — Max results (1-50, default 10)
  • --product — Product keyword (resolves to HS codes)
  • --type enum: all|duties|taxes|remedies|ntm — Filter to one data type
  • exactly one of: --hsCode / --product
  • example: trade lookup --exporter US --importer VN --hs-code 730441
  • example: trade lookup --from brazil --to us --product beef --type duties

eximagent usage

Show today's metered spend for the calling account: net charged cents (after refunds), the portion settled on real LLM/vendor usage, estimated, refunded, against the daily cap. (no args)

  • example: eximagent usage

eximagent watch company

Register a proactive watch on a company (by tax id + country, or name); alerts when it imports again or its supplier set changes.

  • --country — company reporting country (ISO 2)
  • --event enum: imports|supplier-change — event to fire on: imports|supplier-change (def imports)
  • --name — company name (used with --country when no tax id)
  • --taxId — company tax id (RUC/NIT/RUT) of the company to watch

eximagent watch list

List the caller's active proactive watches with their ids. (no args)

eximagent watch market

Register a proactive watch on a market (HS6 × destination); alerts on new-entrant, price-shock, volume-spike, or momentum events as the corpus updates.

  • --dest — destination country (ISO 2) — the market to watch
  • --event enum: new-entrant|price-shock|volume-spike|momentum — event to fire on: new-entrant|price-shock|volume-spike|momentum (def new-entrant)
  • --hs6 — HS code (6-digit) of the market to watch

eximagent watch remove

Remove (disable) one of the caller's watches by id.

  • --id (required) — watch id to remove
Install via CLI
npx skills add https://github.com/EximAgent/cli --skill eximagent
Repository Details
star Stars 2
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator