Skip to content

Run the docs checks in CI and add a runnable-samples lint - #1380

Merged
hmishra2250 merged 8 commits into
mainfrom
ci/checks-workflow
Sep 8, 2026
Merged

Run the docs checks in CI and add a runnable-samples lint#1380
hmishra2250 merged 8 commits into
mainfrom
ci/checks-workflow

Conversation

@hmishra2250

Copy link
Copy Markdown
Contributor

Summary

Adds .github/workflows/checks.yml, the repository's first CI workflow, and a second script for it to run alongside the locale literal lint from #1371.

Opened as a draft. The new script currently fails on this branch, on purpose, and the reason is at the bottom under CI status.

Stack

Targets docs/keep-api-literals-untranslated, the branch of #1371, because that PR ships scripts/check-locale-api-literals.sh and there is nothing for the workflow to run without it. Retarget to main once #1371 merges.

Why

DI-2026-09-05-WEEKLY, paths IP-D6 and IP-D8, reconciled plan items 12 and 14.

There are no workflows in this repository at all. git ls-tree -r origin/main --name-only .github/ returns one PNG. The lint added in #1371 therefore runs only when someone remembers to run it, which is the same as not having it.

The workflow deliberately does not copy the pattern in firecrawl-web's .github/workflows/test.yml, which is pull_request: branches: [main]. A pull request stacked on another pull request's branch fires no pull_request event under that filter and gets no checks at all. This repository's docs stacks routinely target a sibling branch, this PR included, so the filter is left out and every pull request runs.

Changes

  • .github/workflows/checks.yml. Trigger pull_request with no branches filter. permissions: contents: read. Not pull_request_target, because the workflow runs code from the branch, and no secret is passed to it. Node 22 pinned with actions/setup-node@v4. Two steps, one per script. A concurrency group cancels superseded runs on the same pull request.
  • scripts/check-extraction-hostile-markdown.sh. New. Checks that a published shell sample runs as written.
  • scripts/check-locale-api-literals.sh. One comment line updated, from "This repository has no CI workflows" to a pointer at the workflow. No logic change.
  • features/browser.mdx and snippets/v2/monitor/check/get/curl.mdx. Three samples that used a variable they never set now set it.

What the new script checks

  1. Undefined shell variable. A $VAR used inside a bash, sh, shell, zsh, console or curl fence with no assignment anywhere in the same fence. $FIRECRAWL_API_KEY is the only allowed name: it is the reader's own credential and every sample expects it in the environment. Assignments are recognised from NAME=, export NAME=, for NAME in and read with any flags and any number of names. Positional parameters and the usual shell-provided names are not flagged.
  2. Raw i18n token. A translation placeholder such as {locale} or a General Translation component such as <GTProvider> left in published markdown. Zero occurrences today, so this is a regression guard.
  3. Escaped link target. A backslash that survived a markdown escape into a link URL. Zero occurrences today, also a regression guard.

The script reads the English tree only. The localized trees are regenerated by the translation pipeline, so a finding there is fixed in the pipeline or in the English source, never by hand editing a localized file, which CLAUDE.md forbids.

Bare placeholders are not flagged, and the plan's caution about them does not apply. SCRAPE_ID in a URL path and fc-YOUR_API_KEY in a header are literals with no $, so the rule never sees them. The two conventions do not collide anywhere in this corpus.

One rule was checked and dropped. A link anchor containing a literal +, such as #persistent-profiles-with-scrape-+-interact, looks like an escaping artefact and is not one. curl -s https://docs.firecrawl.dev/features/interact | grep -oE 'id="[^"]*persistent[^"]*"' returns id="persistent-profiles-with-scrape-+-interact", and a + in a URL fragment is not decoded as a space. Flagging it would have failed a working link on #1364 and #1369, so it is not flagged and the script says why.

Counts

scripts/check-locale-api-literals.sh:

Tree Findings Exit
origin/main at 73103de7 19 1
this branch 0 0

The 19 on main are what #1371 fixes. This branch inherits those fixes, so the lint is already green here.

scripts/check-extraction-hostile-markdown.sh:

Tree Findings Exit
origin/main at 73103de7 10 1
this branch 7 1
#1369's branch, script run against it 3 1
this branch plus #1369 0 0

All 10 on main are undefined shell variables, and all 10 are real. Three are fixed here: $CDP_URL in features/browser.mdx:345, and $MONITOR_ID and $CHECK_ID in snippets/v2/monitor/check/get/curl.mdx:2. The other seven are the $SCRAPE_ID uses in the interact curl snippets, which #1369 already fixes with its "Define SCRAPE_ID in the interact curl samples" commit. Neither branch can see the other's fixes, so the two sets are disjoint and complementary, verified by running this script inside #1369's worktree.

CI status

Draft, because the new check fails on this branch with the seven $SCRAPE_ID findings that live on #1369's branch. It goes green once #1369 merges and this branch is rebased onto main. Marking this ready before then would mean either a red required check or a check that does not gate.

Making the check required

Turning this into a required status check is a repository settings change on the branch protection rule for main, not something this PR can do. Do that after the first green run, using the check name "Locale literals and extraction-hostile markdown".

🤖 Generated with Claude Code

https://claude.ai/code/session_01SL5chNkWnr4Gy6uuB8PeKS

hmishra2250 and others added 5 commits September 6, 2026 15:19
The Spanish, French and Portuguese trees translated the scrape format
name changeTracking into seguimientoDeCambios, suiviDesModifications and
rastreioDeMudancas. The API accepts only changeTracking, so every code
sample carrying the translated name fails when a reader copies it, and
the CLI --format tables list a flag value that does not exist.

Inside code fences, inline code and quoted strings the name is now
changeTracking again. Sentences that describe the feature rather than
name the format keep prose in their own language.

Finding OB-01 in DI-2026-09-04-WEEKLY reported this for French only. It
is also present in Spanish and Portuguese.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SL5chNkWnr4Gy6uuB8PeKS
The Spanish webhooks page documents the event as crawl.started in its
table and then sends "type": "rastreo.iniciado" in the JSON payload
right below it. A handler written from that payload never matches the
event the API sends.

Finding OB-09 in DI-2026-09-05-WEEKLY, quoting the page: "type":
"rastreo.iniciado" next to | `crawl.started` | El trabajo de rastreo
comienza a procesarse |.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SL5chNkWnr4Gy6uuB8PeKS
The page declares const scrapedData in its first sample and
const dadosRaspados in the second. The English page uses scrapedData in
both. Translating an identifier inside a code sample makes the two
snippets disagree for no benefit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SL5chNkWnr4Gy6uuB8PeKS
Nothing in the repository stops a translation pass from rewriting an
identifier inside a code sample, which is how changeTracking and
crawl.started reached readers translated.

scripts/check-locale-api-literals.sh compares the identifiers used
inside code fences and inline code between each localized .mdx and its
English counterpart. It reports an API identifier the English page uses
in code and the localized page has dropped, and any identifier-shaped
token a localized page uses in code that no English page uses anywhere.
The vocabulary for the first check comes from the OpenAPI specs, so it
follows the API instead of a hand-written list. Example domains are
allowlisted.

The repository has no CI workflows, so the script header says when to
run it: before merging a change to the localized trees, and after every
translation sync. It uses only git, jq and awk, the same tools as
scripts/check-hosted-mcp-docs.sh, and takes about three seconds.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SL5chNkWnr4Gy6uuB8PeKS
The repository has no CI workflows, so the locale literal lint added in
#1371 only runs when someone remembers to run it. This adds
.github/workflows/checks.yml and a second script for it to run.

The workflow uses pull_request with no branches filter. firecrawl-web's
test.yml filters on branches: [main], which means a pull request stacked
on another pull request's branch fires no event and gets no checks at
all. The docs stack routinely does that, so the filter is left out.
Permissions are contents: read, the trigger is pull_request rather than
pull_request_target because the workflow runs code from the branch, and
no secret is passed. Node 22 is pinned.

scripts/check-extraction-hostile-markdown.sh checks that a published
shell sample runs as written. An agent or a person who copies a sample
out of the docs runs it as it stands, and a sample that uses a variable
it never sets fails on the first line. The script flags a $VAR used
inside a bash, sh or shell fence with no assignment in the same fence,
allowing only $FIRECRAWL_API_KEY, which is the reader's own credential.
Bare placeholders that are not shell variables, such as SCRAPE_ID in a
URL path or fc-YOUR_API_KEY in a header, are not shell variables and are
not flagged. It also flags raw i18n tokens and a backslash left inside a
link target. It reads the English tree only, because the localized trees
are regenerated and a finding there is fixed upstream.

One rule was considered and dropped. A link anchor with a literal +, such
as #persistent-profiles-with-scrape-+-interact, looks like an escaping
artefact and is not one: the rendered heading on docs.firecrawl.dev
carries exactly that id. Flagging it would fail a working link.

Three findings are fixed here so the new check can gate: features/browser.mdx
never set CDP_URL, and snippets/v2/monitor/check/get/curl.mdx never set
MONITOR_ID or CHECK_ID.

Findings: DI-2026-09-05-WEEKLY IP-D6 and IP-D8, reconciled plan items 12
and 14.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SL5chNkWnr4Gy6uuB8PeKS
@hmishra2250
hmishra2250 changed the base branch from docs/keep-api-literals-untranslated to main September 8, 2026 06:40
@mintlify

mintlify Bot commented Sep 8, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
firecrawl 🟢 Ready View Preview Sep 8, 2026, 6:47 AM

💡 Tip: Enable Automations to automatically generate PRs for you.

# Conflicts:
#	fr/features/monitoring.mdx
…mat name

The 2026-09-07 locadex pass rendered the `changeTracking` formats value as
`suiviDesModifications`, which is not a value the API accepts. Restore the
English literal so the sample runs as written.
@hmishra2250
hmishra2250 marked this pull request as ready for review September 8, 2026 06:50
@hmishra2250
hmishra2250 merged commit 9a8730a into main Sep 8, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant