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
eximagent whoami— confirm auth (runeximagent loginif it fails).eximagent profile get— see the operator profile that grounds every later turn.eximagent hscode search --query "<product>"— disambiguate HS code if the user did not give one.eximagent search run --product "<product>" --location <country>(preview) →--confirmedto start.eximagent collection get --name <name>→eximagent enrich company --url <url>for the standouts.eximagent enrich contacts --collectionId <id>(filter-free first pass) →eximagent email draft --dry-run→ confirm →eximagent email send --confirm.- 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:
- Ground in auth and profile
- Clarify product, market, and HS code if needed
- Run buyer search (preview → confirm → stream)
- Inspect results and shortlist
- Enrich company data on the shortlist (
enrich company) - Enrich contacts only for validated targets (
enrich contacts) - Draft outreach (
email draft --dry-runfirst)
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 / distributors →
profile getto ground → clarify product + market + HS →hscode searchif HS unknown →--dry-run search runpreview → confirm →search run --confirmed(capturerunIdfrom the kickoff response) →stream --run-id <runId>and BLOCK until the terminalcompleteevent before reading rows - Look up tariff → if HS is known:
tariff --exporter --importer --product; otherwisehscode searchfirst - Custom duties / NTM measures / remedies →
trade lookup --type duties|taxes|remedies|ntm|all - Identify a company from a name →
company --name "..."(single) or--inputs file.ndjson(bulk) - Profile a website →
enrich company --url ...(single) or--inputs file.ndjson(bulk). For just raw markdown without structuring:crawl --url ... - Screen against sanctions →
sanctions 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 companyfor the list → pass the returnedkeyFacts.imagesURLs to your host's vision tool - A list of N companies / URLs / HS queries → ALWAYS use
--inputsbulk shape, never loop - Who actually ships / imports / exports a product →
product shipments --hs_code <code>orshipments search --hs6 <6digit> --dest <iso2>— real per-shipment customs records, not a model guess - A company's real shipment history →
company shipments --name "<company>"(matches exporter or importer) - Trade flowing on a route / lane →
route shipments --origin <iso2> --dest <iso2> - Price / value evidence for a product →
price shipments --hs_code <code> [--min_weight_kg N] - One shipment's full record or raw provenance →
shipments 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:
- Push the computation down (default).
analytics query(structured groupBy × measures × filters) andanalytics 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. Readanalytics catalogfirst for the schema. - Pull raw rows only when you truly need row-level data. Both
analytics queryandanalytics sqlpage the entire result set: each full page returns anextActionsnext-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; setsconfirmed=false+dryRun=trueserver-side. Safe wrapper for any billable / irreversible command.--profile <name>— switch saved account. Same asEXIMAGENT_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 foranalytics 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:
- 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.
- Run
eximagent profile getfirst to ground in user defaults (product, targets, signature, incoterm, timezone). - Preview billable / irreversible calls with
--dry-runand present the plan + expected cost before confirming. - Never blind-retry
INVALID_ARG. That is your bug; readerror.details.expectedanddid_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: "
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
--strictto 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:
- After ANY tool returns successfully, read
nextActions[]BEFORE replying to the user. - If exactly one action is
free/lowcost AND the user's original ask covers this step, auto-execute itscommandWITHOUT confirming. - Otherwise surface
nextActions[]to the user as a numbered pick list — one line each, usinglabel+cost. - NEVER say "I'm done" if
nextActionsis 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 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.
- Plan card before the first billable step. Format: numbered step list with ETA + cost forecast per step, total ETA, total cost forecast, captured scope.
- Per-step ENTRY before each tool call:
[2/4] enriching 30 companies on shortlist... - Per-step EXIT after each tool returns:
[2/4] done · 30 enriched · 28 with valid website · 2 unreachable · 78s · $0.61 cumulative - Decision rationale when picking a non-obvious branch:
"Picking enrich-company before enrich-contacts because contacts need company data" - 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 andeximagent run summary <runId>for the per-stage counts + total cost when it finishes.run statuscarries live progress mid-run:companiesProcessed(agrees withcollection get),expectedCompanies,percentComplete,stage, andlastHeartbeatAt— 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>.examplewas 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 getdoes 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
--stricton single calls; in bulk, auto-pick proceeds and the user can auditautoResolvedrows after). email sendis 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
--inputsbulk shape. - Enriching contacts on a 300+ raw collection before shortlisting. Always shortlist by priority or score first.
- Treating
extractedemails / 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: 0whilestatus: running) → NORMAL, not failure. Results land only at the terminalcompleteevent.stream --run-id <runId>or pollrun status <runId>and BLOCK on terminal before reading rows. Do NOT declare failure, do NOT re-runsearch run. BUSYon the user context → waitretryAfterMs, retry. Surface a one-line "in-flight elsewhere, retrying in Ns" breadcrumb.- Preview text contradicts intent →
--direction buyers|sellersmakes the intent explicit. Re-issue the preview before paying. - Bulk row count smaller than input → check
failedcount + per-rowstatus. Re-run only the failed indices. enrich contactsreturns 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
autoResolvedpick → re-run that one row with--strict(single) and let the user pick fromalternatives.
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
autoResolvedpick 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
failedcount + per-rowstatusand 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 product →
profile get→hscode search --query "<product>"→--dry-run search run --product "<product>" --location <country> --hsCode <code> --direction buyers→ confirm →search run ... --confirmed(capturerunId) →stream --run-id <runId>until terminalcomplete→ shortlist--priority high --limit 25→enrich 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 countries →
hscode search --query "<product>"→tariff --exporter <code> --importer <code> --product "<product>"→ optionallytrade lookup --exporter <code> --importer <code> --hsCode <code> --type all. - Multimodal triage of a bulk-enriched list →
enrich company --inputs companies.ndjson→ for eachrow.output.keyFacts.images, route URLs to host vision tool → answer "which look like specialty roasters" image-grounded.
Known limitations
linkedin lookupworks 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 contactsis 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.
--strictis 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 viatemplate 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 viacorridor 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 lastemail draftpreview. 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 viakb 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 viamonitor 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 viaproducts 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:
--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-
--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 viareminder 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 byexim 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 viatemplate 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 viatemplate 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