| name | nimble-web-search-agents-reference |
| description | Reference for Nimble Web Search Agents (Agent API V2). Load when a task needs open-ended
research, enrichment, or dataset building โ where the source isn't fixed, data is
scattered, structure is inconsistent, or a synthesized answer is needed.
Covers: the three run modes, dynamic discovery, the reuse-priority chain, `use_case`
locking, run-level `skill` override, run controls, live events vs polling, trust and
citations, and safe credentials.
|
nimble agents โ Web Search Agents reference
A Web Search Agent is Nimble's AI-driven agent for open-ended web work. Given a goal, it
discovers where the information lives, navigates to it, and returns a structured or written
result with per-claim citations โ rather than being pointed at a fixed set of URLs. It serves
three use cases: research, enrichment, and dataset building.
Use a Web Search Agent when at least one is true: the source isn't known or varies and must be
discovered; the data is scattered across sources that may not be specified; page structure is
inconsistent enough that fixed parsing won't work and the tool needs to reason about what it
finds; or free-text synthesis is needed (a report or summary, not just raw results). When a
single known page can be parsed directly, prefer an Extraction Template
(references/nimble-extract-templates/SKILL.md); for raw results to work from, use
nimble search.
Requires Nimble CLI 1.2.0+. REST/SDK surface: POST /v2/agents/*. Credentials: read
NIMBLE_API_KEY from the environment only โ never echo, log, or paste a key into a prompt,
params, or output.
Table of Contents
Run modes โ pick one before anything else
Which identity you pass on the run decides which route runs, and which route you're on
decides which command to call. Choose the mode first, then build the command.
| Mode | Identity passed | Command | Use when |
|---|
| 1 โ named create-or-reuse | --agent-name, no agent ID | nimble agents run --agent-name <name> | Default for skills. A stable name you can re-derive each session without storing an ID. |
| 2 โ explicit agent | --agent-id | nimble agents:runs create --agent-id <id> | You already manage the agent's lifecycle (materialized from a template or authored from scratch). |
| 3 โ caller-anonymous | neither | nimble agents run | A genuine one-off where no agent needs to survive the run. |
Routing rule: agents:runs create requires --agent-id โ it is the Mode 2 command
only, and --agent-name is ignored there. Modes 1 and 3 both go through nimble agents run.
Mode 1 reuse is by name, and it is exact. An unseen name creates a new agent; a name
already in the account resolves to that agent and returns the same web_search_agent_id
on every subsequent run. Derive names deterministically (e.g. {skill}-{purpose}) so a
repeat session lands on the same agent instead of littering the account with near-duplicates.
Mode 3 still creates an agent. The response carries a generated web_search_agent_id โ
keep it, because agents:runs get and agents:runs result both need it.
Every mode returns the same run envelope: id (= interaction_id), status,
web_search_agent_id, effort, prompt.
nimble --client-source nimble-agent-skills agents run \
--agent-name "competitor-intel-news" --use-case research \
--input "<task or question>" --effort high
nimble --client-source nimble-agent-skills agents:runs create \
--agent-id <agent_id> --input "<task or question>" --effort high
nimble --client-source nimble-agent-skills agents run \
--input "<task or question>" --effort high
use_case โ set once, then locked
Exactly three values: research, enrichment, dataset_building. Nothing else
is accepted โ a wrong value fails validation with the accepted enum echoed back.
use_case is agent configuration, not a per-run override:
- It is stored when the agent is created โ including on a Mode 1 first call and on a
Mode 3 run.
- Against an existing agent, passing the same value is accepted as a no-op.
- Against an existing agent, passing a different value is rejected (
422,
use_case cannot be changed for an existing agent). Omit it, or match it.
Read an agent's stored value with agents get --agent-id <id> before running if you're not
sure. To work in a different use case, use a different agent โ don't try to flip an
existing one.
dataset_building carries two extra requirements, both enforced server-side:
--output-schema is required (output_schema is required when use_case is dataset_building).
- Effort must be
high or above (dataset_building requires effort 'high' or higher).
skill โ a one-time run override
--skill is the agent's domain-expertise prompt. On a run it behaves differently from
use_case:
- Against an existing agent (Mode 2, or Mode 1 on a name that already resolves),
--skill
applies to that run only. The agent's stored skill is left untouched โ verified by
re-reading the agent after an override run.
- First-call exception: when the run is the call that creates the agent (Mode 1 with an
unseen name, or Mode 3),
--skill and --use-case are not overrides at all โ they become
the new agent's stored configuration.
So the same flag means "just this once" or "from now on" depending on whether the agent
already existed. When it matters, check with agents get first.
Run controls
Available on both agents run and agents:runs create:
| Flag | Description |
|---|
--input | Natural-language task/question for the run (required) |
--effort | low / medium / high / x-high / max (see below) |
--output-schema | JSON schema (a full mapping) overriding the agent's default structured output |
--input-data | Existing rows to ENRICH โ a list or single object mirroring the output_schema shape |
--sources | Source guidance overriding the agent default |
--enable-events | Publish live progress; consume with agents:runs stream-events |
--previous-interaction-id | Continue a prior run as a conversation (pass the earlier run's interaction_id) |
--skill / --use-case | Per the two sections above |
--sources โ four fields, two different shapes
{
"allow": [{ "title": "Reference encyclopedias", "domains": ["example.com"], "order": 0 }],
"block": [{ "title": "Social pinboards", "domains": ["example.net"], "order": 0 }],
"prioritize": "Prefer the organization's official site over aggregators.",
"avoid": "Avoid unsourced blog aggregators."
}
allow / block are arrays of source groups โ objects with title (required),
domains, and an optional order that sets priority. A bare domain string is rejected.
prioritize / avoid are plain guidance strings. An array is rejected.
allow is a hard whitelist; prioritize/avoid are soft steering. Prefer a domain already
covered by an Extraction Template โ the agent gets cleaner structured data there.
--input-data vs --output-schema โ they are not the same thing
--output-schema describes the shape of the answer.
--input-data supplies the rows you already have, mirroring that shape; the agent fills
the gaps rather than re-deriving what you gave it.
Two things to get right:
- Enriching several rows needs an array
output_schema. An object schema returns one
object no matter how many rows go in.
- Fields carried in from
input_data come back in trust.claims with
confidence: "pre_existing" and no citations โ they were passed through, not verified.
Don't present them as sourced findings.
Discovery and the reuse-priority chain
Before creating a new agent, check in this order:
- Existing agent already covers this โ
nimble agents list, reuse its id (Mode 2), or
just re-run its agent_name (Mode 1).
- Close-match agent template worth materializing โ
nimble agents:templates list, then
nimble agents create --template <template_name>.
- Only if neither fits, create one from scratch.
nimble --client-source nimble-agent-skills agents list --limit 100
nimble --client-source nimble-agent-skills agents:templates list
nimble --client-source nimble-agent-skills agents:templates get --template-name <template_name>
Neither agents list nor agents:templates list takes a server-side search term โ list and
filter client-side on agent_name / template_name / description / use_case. Names
are dynamic: discover them at runtime, never hardcode them.
Each template carries template_name, display_name, description, use_case, a default
effort, a skill, sources, goals, and an output_schema. Read these to judge fit
before materializing. Note the template sources shape differs from the run/agent shape โ
it is a flat ordered array of {title, domains, order} groups.
nimble --client-source nimble-agent-skills agents create --template <template_name>
Key agents create flags: --agent-name (stable name), --display-name,
--description, --goal (repeatable, ordered), --sources, --output-schema, --effort,
--skill, --suggested-question (repeatable), --use-case, --template, --is-active.
Run lifecycle: create โ status โ result
Runs are asynchronous: create, reach a terminal state, then fetch the result.
nimble --client-source nimble-agent-skills agents:runs get \
--agent-id <agent_id> --run-id <run_id>
nimble --client-source nimble-agent-skills agents:runs result \
--agent-id <agent_id> --run-id <run_id>
Run states: queued โ (running) โ terminal: completed, failed, or cancelled. List
an agent's runs newest-first with nimble agents:runs list --agent-id <id>.
Fetching result before the run is terminal returns 409 โ "Run still active; poll the run
status endpoint". That is a timing signal, not an error to retry blindly: go back to
agents:runs get.
Live progress: events, and polling as the fallback
On the CLI, events work (verified on 1.2.0). Create the run with --enable-events, then
consume the stream:
nimble --client-source nimble-agent-skills agents run \
--agent-name <name> --enable-events --input "..." --effort high
nimble --client-source nimble-agent-skills agents:runs stream-events \
--agent-id <agent_id> --run-id <run_id> [--max-items <n>]
Events arrive as JSON objects with a type: task_run.state (carries the run's status),
task_run.progress_msg.* (exec_status, plan, โฆ), and task_run.progress_stats (source
counts and a sample of URLs read).
Termination behavior: the stream closes on its own once the run reaches a terminal
state โ the final task_run.state event carries completed. --max-items <n> closes it
after n events instead, leaving the run going. Either way the stream never carries the
output: fetch agents:runs result after it closes.
On MCP, use bounded status polling instead โ the shell-less transport works on
request/response, so poll nimble_agents_run_status every ~15โ30s, cap the total wait, and
report the run as still active if the cap is hit rather than hanging or declaring failure.
Polling is also the right approach in any host that can't hold a long-lived stream open.
Effort tiers
Set effort to the shape of the task โ don't ask the user to pick a number:
| Tier | When |
|---|
low / medium | Fast, simple asks โ a handful of easy-to-find fields |
high | Default once several fields need real digging |
x-high / max | Genuinely complex, multi-faceted profiles (financials, filings, history) |
dataset_building runs will not accept anything below high.
For a quick first look, offer a preview run at low, then re-run at the recommended tier โ
the user chooses "quick preview" vs "full run" without ever touching the value.
Authoring a from-scratch agent
When creating from scratch, fill each field deliberately (adapted from Nimble's own agent
configuration guidance):
- Domain Expertise (
--skill) โ a dense role paragraph, under five sentences: who the
agent is for this use case; how to handle inputs supplied in more than one format; which
source to check first for which fact; how to handle data that can't be found (say
"Unknown," never invent); and whether to return a per-field confidence indicator.
- Goals (
--goal, repeatable) โ one verb phrase per logical group of output fields,
ordered most-important first. If there's a way to skip re-fetching data the user already
has, make that the first goal.
- Sources (
--sources) โ priority-ordered groups per the shape above, most important
first.
- Output (
--output-schema) โ use the user's own field names; use plain strings for
ranges/estimates ("50 to 200 employees", not an invented number); group related fields into
nested structures and use lists for anything naturally a list; mark required vs optional.
- Use case (
--use-case) โ pick deliberately; it locks on creation.
- Effort โ per the tiers above.
Also draft a recommended starting prompt for the first run based on the conversation.
Trust & citations
agents:runs result returns an output that is either type: "text" (a prose answer) or
type: "json" (structured data matching the output schema), plus trust metadata:
trust.sources โ every source used, with title, url, type, and source_category.
trust.claims โ per-claim citations with excerpts and a confidence. Structured outputs
anchor each claim to a JSON path ($.founded_year); text outputs anchor to a numbered
callout in the prose.
trust.confidence + trust.reasoning โ a run-level judgement and why.
Surface the citations alongside the answer โ every claim should trace to a source. This is
what makes a Web Search Agent's answer verifiable rather than an unsourced summary. Treat
confidence: "pre_existing" claims as caller-supplied input, not findings.
MCP fallback โ transport differences
Shell-less hosts use the production Nimble MCP server. Run parameters carry over โ the run
tool takes agent_id, agent_name (create-or-reuse, same semantics as Mode 1), use_case,
skill, sources, output_schema, input_data, and effort.
One routing rule to know: nimble_agents_run takes either agent_id or
agent_name โ always pass one. Sending neither returns "Provide either agent_id (run an
existing agent) or agent_name (create-or-reuse by name)." On MCP, then, reach for a
Mode 1 agent_name wherever you'd have used Mode 3 on the CLI. That's the better default
anyway: a named agent is reusable next session, which is exactly what Mode 3 gives up.
| Capability | CLI | MCP |
|---|
| Mode 1 โ named create-or-reuse | โ
| โ
(nimble_agents_run + agent_name) |
| Mode 2 โ explicit agent | โ
| โ
(nimble_agents_run + agent_id) |
| Mode 3 โ caller-anonymous | โ
| Pass an agent_name โ one identity is required |
| Discovery / inspect | โ
| โ
(nimble_agents_list, nimble_agents_get, nimble_agent_templates_list / _get) |
| Status โ result | โ
| โ
(nimble_agents_run_status, nimble_agents_run_result) |
| Live events | โ
--enable-events + stream-events | Use bounded status polling instead |
previous_interaction_id | โ
| Start a fresh run with the prior context restated in input |
--client-source nimble-agent-skills | โ
on every call | Attributed at the transport level โ don't try to override it |
Failure handling
| Signal | What it means | Do this |
|---|
409 "Run still active" | Fetched result before the run finished | Go back to agents:runs get; don't hammer result |
404 "Run 'โฆ' not found for agent" | Wrong run_id/agent_id pairing | Re-read the IDs from the create response |
422 use_case cannot be changed for an existing agent | Locked use_case mismatch | Omit --use-case, match it, or use a different agent |
422 "Input should be 'research', 'enrichment' or 'dataset_building'" | Invalid enum value | Use one of the three exactly |
422 output_schema is required when use_case is dataset_building | Missing schema on a dataset run | Supply --output-schema |
422 dataset_building requires effort 'high' or higher | Effort too low for a dataset run | Raise to high or above |
422 on sources | Wrong shape, or a group missing title | allow/block = arrays of objects, each with a title; prioritize/avoid = strings |
Required flag "agent-id" not set | Used agents:runs create for a Mode 1 / Mode 3 run | Switch to nimble agents run |
Run reaches failed / cancelled | A real outcome | Report it plainly; suggest broadening sources or raising effort |
- Poll
agents:runs get until a terminal state; don't fetch result before completed.
failed / cancelled are real outcomes โ report them plainly, don't present a partial or
empty result as success. Suggest an obvious next step (broaden sources, raise effort, or a
different capability) where one exists.
- Never work around a missing/blocked transport with WebFetch, WebSearch, or curl.