DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Web Firecrawl — DSH Plugin for DeepSeek Harness
← Plugins

dsh-web-firecrawl

Web Firecrawl

Firecrawl as the DeepSeek Harness web backend: query routing, on-demand enrichment, credit budgets and failure memory for web_search/web_fetch.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add dsh-web-firecrawl@0.1.1
READMECompatibilityVersions

Compatibility and provenance

Web Firecrawl is published as dsh-web-firecrawl and currently resolves to version 0.1.1. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
any
Release source
npm
Registry updated
10/2/2026

Versions

0.1.1stable
10/2/2026
0.1.0stable
10/2/2026

Related plugins

Loading related plugins…

Latest
0.1.1
DSH
*
HMR
Process restart
Tree shaking
Declares sideEffects: false
Unpacked size
67.3 kB
Files
7
Surface
any
License
MIT
Source
npm
GitHub
★ 0
Weekly downloads
0
Last push
10/2/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in

Related plugins

More verified plugins in search-research.

Weknora@wxg-prc-cpg/dsh-weknoraWeKnora knowledge retrieval tools for DeepSeek Harness (dsh): semantic search, document reading and RAG/agent answers over your own knowledge bases.Free Searchdsh-free-searchFree web search for DeepSeek Harness: 24 engines (Bing/DuckDuckGo/AnySearch/SearXNG/Exa/Tavily/Keenable/Firecrawl/Parallel keyless; Zhihu global/site via MCP and Perplexity/SerpBase/DeepSeek/You.com/Baidu/Kimi/Aliyun/Doubao with key; OpenAI/Gemini/Claude Dejadsh-dejadeja-vu memory for DeepSeek Harness: the session history of forty other coding agents, searchable and recalled before each step — a local index, no LLM.Builtin Browserdsh-builtin-browserShared real browser plugin for DeepSeek Harness: install-and-use — a visible native browser the human can take over, driven by the agent over CDP. DOM-level interaction (React/Vue safe), per-task session isolation, cookie persistence (dsh_browser_auth), C

README

dsh-web-firecrawl

Firecrawl as the web backend for DeepSeek Harness. It adds no new tools: web_search and web_fetch keep working exactly as before, and this plugin decides how they talk to Firecrawl.

dsh plugin --profile web add dsh-web-firecrawl

Why this exists

The official @firecrawl/dsh-firecrawl pins peerDependencies to @deepseek-ai/dsh-web@0.1.0-rc.6. DeepSeek Harness 0.2.0 added a compatibility preflight that refuses any plugin whose @deepseek-ai/dsh* peers do not match the running runtime — so the whole bundle is skipped, its patch layer is dropped, and web_search silently falls back to a different backend.

This package declares no @deepseek-ai/* peer dependencies at all (and imports nothing from them either). The preflight only reads peerDependencies, so it has nothing to refuse and the plugin keeps working across dsh upgrades.

It also does more than forward a query:

official 0.1.0this package
loads on dsh 0.2.x❌ refused by the preflight✅ zero dsh peers
categories (research / developer / pdf)❌ not in its parameter surface✅ inferred from the query, free
site: / -site: operators❌ passed through as text✅ become hard includeDomains / excludeDomains filters
result qualityonly description (~200 chars)✅ top-K upgraded on demand with summary (+1 credit, 4–7× the text); question returns an actual answer into the seam's content
repeated queries / URLsbilled again every time✅ in-process cache, 0 requests for 10 minutes
dead-end URLsretried by the model✅ failure memory denies a repeat of a URL that cannot improve
credit safetynone✅ accounts real creditsUsed; auto-detects metered vs self-hosted
tool routingnone✅ a system-prompt table for when to use which Firecrawl MCP tool

Install

dsh plugin --profile web add dsh-web-firecrawl

dsh plugin runs pnpm inside the profile and registers the bundle in dsh.profile.bundles automatically. Restart dsh afterwards — profile config is composed at boot.

Point it at your Firecrawl endpoint (project .env or the launching environment):

# self-hosted Firecrawl — no API key needed
FIRECRAWL_BASE_URL=https://firecrawl.example.com

# or the public API
FIRECRAWL_API_KEY=fc-your-key

Verify:

dsh --profile web --dump-config | grep -A3 '^- id: web$'
# want: searchProvider: firecrawl / fetchProvider: firecrawl

If you leave FIRECRAWL_BASE_URL unset you get the public, metered API at https://api.firecrawl.dev. The plugin detects that, enables its credit caps, and logs a warning once — but that is already after money can be spent. Set the endpoint.

Why the endpoint is not in the shipped config

cordis patches replace a config object rather than merging it (target[key] = value). If this package shipped a baseURL in its patch, anyone who wrote their own config: for the same entry would silently drop it and fall back to the public metered API. Endpoint and credential therefore come from the environment, which DSH resolves through its launch-environment snapshot.

What it does with a query

  1. Free filtering first. Query intent picks a Firecrawl categories channel (research, developer, pdf); site: / -site: become includeDomains / excludeDomains and are stripped from the query text. limit is rounded up to the next 10-result band, because search bills 2 credits per 10 results — extra recall in the same band is free.
  2. On-demand enrichment instead of blanket scraping. scrapeOptions bills per result, so scraping all eight is wasteful. The plugin scrapes only the top K (enrichTopK, default 1) and only when the free snippets look thin (enrichMode: adaptive). summary costs +1 credit and returns 4–7× the text; question costs +4 and returns a generated answer.
  3. A credit budget that matches reality. /v2/team/credit-usage tells the plugin whether this backend bills at all: the public API and paid proxies answer with balance data, a self-hosted instance answers 500 UNKNOWN_ERROR and even accepts a bogus key. Metered backends get credit caps; unmetered ones only get a runaway-call guard.
  4. Failure memory. Unreachable sites, 404s, paywalls and empty pages are remembered, and a repeat fetch is denied with an instruction to change the source. Network wobble, 429 and 5xx are never remembered — those are worth retrying.

Configuration

Every key is optional. Set them on the web-firecrawl entry in your profile's cordis.patch.yml — remember that a config: block replaces the whole config, so repeat any value you want to keep:

- id: web-firecrawl
  config:
    enrichTopK: 1              # upgrade the top K results; 0 = bare search (cheapest)
    enrichFormat: summary      # summary (+1) | markdown (+1) | question (+4)
    enrichMode: adaptive       # or 'always'
    budgetWindowCredits: 60    # metered backends only: credits per 10 minutes
    budgetWindowCalls: 120     # both: runaway-loop guard
    minRemainingCredits: 0     # metered backends: stop when the balance drops below this
    failureTtlMs: 600000       # dead-end memory TTL; 0 = off, negative = until restart
    billingMode: auto          # auto | metered | unmetered
    routingPrompt: true        # publish the tool-choice table in the system prompt
All options
keydefaultmeaning
baseURLhttps://api.firecrawl.devendpoint; FIRECRAWL_BASE_URL wins over it
apiKey$FIRECRAWL_API_KEYomit entirely for self-hosted / rotating proxies
timeoutMs60000per-request Firecrawl budget
searchBudgetMs25000wall clock for one whole search(), enrichment included
enrichTopK1results to upgrade on demand
enrichFormatsummarysummary / markdown / question
enrichQuestion—question text when enrichFormat: question
enrichModeadaptiveupgrade only when snippets are thin, or always
thinSnippetChars160"thin" threshold for adaptive mode
maxSnippetChars1400cap on a snippet handed to the model
enrichTimeoutMs20000cap for one enrichment scrape
enrichMinRemainingMs8000skip the upgrade rather than abort mid-flight
inferCategoriestrueinfer categories from the query
parseSiteOperatorstrueturn site: into domain filters
onlyMainContenttrue

Making enrichment land reliably

An enrichment scrape can take 6–33 s. dsh-tool-web defaults searchTimeoutMs to 30 s and kills the call past it, so the plugin's searchBudgetMs stays under that and skips the upgrade rather than starting one it cannot finish (an aborted scrape is still billed). To get enrichment every time, raise both sides:

- id: tool-web
  config:
    searchTimeoutMs: 60000
- id: web-firecrawl
  config:
    searchBudgetMs: 50000
    enrichTimeoutMs: 45000

Fleet deployment

One command per person, and bundle registration is automatic:

dsh plugin --profile web add dsh-web-firecrawl                            # from npm
dsh plugin --profile web add git+ssh://git@host/org/repo.git#v0.1.0       # from git
dsh plugin --profile web add /srv/pkgs/dsh-web-firecrawl                  # from a shared directory
dsh plugin --profile web remove dsh-web-firecrawl                         # rollback

The endpoint is deployment-wide, so hand it out through the environment (FIRECRAWL_BASE_URL in a project .env) rather than through per-user patches.

Health check across a fleet:

dsh --profile web --dump-config | grep -A3 '^- id: web$'

Troubleshooting

symptomcause
web_search returns results from another backendthe bundle is not mounted: check searchProvider in --dump-config
skipping profile bundle at boota denied bundle is still listed in dsh.profile.bundles; remove it
patch: entry "…" not founda stale patch entry targets an id that no longer exists
every call is slowenrichTopK is upgrading results (see the timeout section above)
budget … exhausteda cap fired; on a self-hosted instance set billingMode: unmetered

Publishing (maintainers)

The package is published to registry.npmjs.org — not GitHub Packages. GitHub's npm registry requires an access token to install even public packages (docs: "You need an access token to publish, install, and delete private, internal, and public packages"), which would turn a one-command install into account + PAT + ~/.npmrc setup for every user.

Releases go through .github/workflows/publish.yml on a v* tag, using npm trusted publishing (OIDC) — no long-lived token, provenance attached automatically. Two one-time steps:

  1. The first version must be published outside CI (npm publish with an OTP). npm has no equivalent of PyPI's "pending publisher": configuring trust for a package that does not exist yet fails with 404 Package not found from POST /-/package/<name>/trust.

  2. Then bind the repository to the package. Either the website (package → Settings → Trusted Publisher → GitHub Actions) or, scriptable:

    npm trust github <package> --file publish.yml --repository <owner>/<repo> --allow-publish
    

    --allow-publish is not optional. Trusted-publisher configurations created after 2026-09-03 default to npm stage publish only; without explicitly allowing direct publishing, a tag-triggered npm publish is rejected. The website equivalent is the "Allow npm publish" checkbox on the Trusted Publisher form.

    Both --file (workflow file name, including the extension) and --repository (which must match repository.url in package.json) are validated only at publish time — npm does not verify them when you save, so a typo surfaces later as ENEEDAUTH. The CLI command needs npm ≥ 11.15.0.

    Then optionally: Settings → Publishing access → Require two-factor authentication and disallow tokens (trusted publishers keep working — they use OIDC, not tokens).

After that, a release is:

npm version patch        # or minor / major
git push --follow-tags   # CI publishes on the v* tag

Tests

npm test              # stub-based suites, no network
npm run test:live     # against a real endpoint: FIRECRAWL_TEST_BASE_URL=...
npm run test:seam     # against real dsh packages: DSH_PACKAGES_DIR=...

Compatibility

No @deepseek-ai/* imports and no @deepseek-ai/* peer dependencies, on purpose. The only contract is the web seam itself:

{ id, available(), search(request, signal) }   // -> { sources[], content?, truncated }
{ id, available(), fetch(request, signal) }    // -> { url, statusCode, body, truncated }

License

MIT

drop boilerplate
blockAdstrueblock ads during rendering
maxAgeMs172800000Firecrawl cache window (speed, not credits)
waitForMs0extra wait before snapshotting
shellWaitForMs2500wait used by the one JS-shell route change
maxBodyChars100000cap on a fetched body
pdfMaxPages20PDF parsing bills per page — this is the brake
cacheTtlMs600000in-process cache TTL (the only thing that saves credits)
failureTtlMs600000dead-end memory TTL; 0 off, negative until restart
billingModeautoauto / metered / unmetered
billingProbeTimeoutMs5000budget for the billing probe
billingProbeTtlMs600000how long a probed verdict is trusted (0 = every call)
budgetWindowMs600000rolling window for both budgets
budgetWindowCredits60credits per window (metered only)
budgetSessionCredits300credits per process (metered only)
minRemainingCredits0stop below this reported balance (metered only)
budgetWindowCalls120calls per window (always)
retryTransport2retries for network wobble
retryRateLimit2retries for HTTP 429 (honours Retry-After)
retryServer1retries for HTTP 5xx
routingPrompttruepublish the tool-choice table

0 is meaningful for every budget/retry knob and disables that limit.