plans/2026-06-27-scout-enhancement-plan.md
Scout CI Acquisition Profile V1
Date: 2026-06-27
Status: Released as Scout 0.1.1. A separate /ci/scrape endpoint was implemented during exploration, rejected as bespoke endpoint debt, and removed. The live direction is now enforced in code: enhance Scout's existing /scrape path with optional acquisition metadata only through shared request/response types, not a separate route.
Capability audit status: Crawl4AI capability and version audit completed on 2026-06-27.
Summary
Scout should expose a focused acquisition metadata profile for Competitive Intelligence pages where browser-grade extraction, clean markdown, JavaScript rendering, screenshots, crawling, or page mapping matter.
The goal is not to force Scout onto every source, and it is not to make Scout a full CI product. The goal is to make Scout a measurable acquisition quality engine that can tell the CI runner whether a captured page is trustworthy enough to use.
Architecture boundary:
/scrape = general-purpose Scout scrape
/scrape with CI acquisition profile/options = scrape + CI cleanup + quality scoring + collector recommendation
There must be no separate CI scrape route. CI behavior must reuse Scout's core acquisition types and Crawl4AI integration inside the existing scrape architecture. As of the 2026-06-27 implementation, POST /ci/scrape returns 404.
Backward compatibility rule:
Existing /scrape callers must not break. Enhanced acquisition behavior must be opt-in through request flags or compatible nullable fields.
Evidence From Smoke Test
Scout performed better than direct HTTP on Google AI blog and Constructor product pages, and provided richer extraction for Coveo/Bloomreach, but it showed three improvement needs:
- API clients must send
X-API-Key. - Consent/cookie boilerplate can pollute markdown.
- RSS feeds should not be processed through generic page scraping.
- Simple static pages may not need Scout because direct HTTP is faster.
Crawl4AI Feasibility Check
Scout is using Crawl4AI as its acquisition engine. The live Scout container now reports:
- Scout version:
0.1.1 - Crawl4AI package version:
0.9.0 - PyPI latest checked from Chowmes on 2026-06-27:
0.9.0
Important correction:
Scout previously reported Crawl4AI 0.7.7 from a hardcoded version constant while the container actually had 0.9.0 installed. This made operational truth unreliable. Scout now reads the installed package version from Python package metadata, and pyproject.toml pins crawl4ai==0.9.0 so future rebuilds do not silently upgrade Crawl4AI without tests.
What Crawl4AI Already Supports
Crawl4AI supports the core primitives needed for this plan:
- Browser rendering through
AsyncWebCrawler. - Browser configuration through
BrowserConfig. - Run-level configuration through
CrawlerRunConfig. - Clean markdown through
DefaultMarkdownGenerator. - Heuristic filtering through
PruningContentFilter. - Structured extraction through
JsonCssExtractionStrategy. - LLM extraction through
LLMExtractionStrategy. - Deep crawling through
BFSDeepCrawlStrategy. - Sitemap/URL discovery through
aseed_urlsandSeedingConfig. - Screenshots and PDFs through run config media flags.
- JS wait conditions through
wait_for,wait_until, and page timeouts. - Stealth/user simulation knobs including
simulate_user,magic,override_navigator, user agent, proxy, and persistent/session options. - Content cleanup knobs including
excluded_tags,excluded_selector,remove_overlay_elements, andremove_consent_popups. - Advanced page handling including full-page scan, iframe processing, shadow DOM flattening, network request capture, console capture, virtual scroll config, retries, and fallback fetch functions.
Are We Using Crawl4AI Optimally?
Not yet.
Scout already uses several good Crawl4AI primitives: AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, PruningContentFilter, DefaultMarkdownGenerator, JsonCssExtractionStrategy, LLMExtractionStrategy, BFSDeepCrawlStrategy, screenshot mode, sitemap mapping, and stealth options.
The CI runner currently calls Scout's existing basic scrape path. Scout does not yet fully use Crawl4AI's best available controls for CI:
- It does not pass
remove_consent_popups=True. - It does not pass
remove_overlay_elements=True. - It does not use source-specific
css_selector,target_elements,excluded_tags, orexcluded_selector. - It does not use
BM25ContentFilteror source-query-focused filtering for noisy pages. - It does not use
capture_network_requestsorcapture_console_messagesfor diagnosing broken dynamic pages. - It does not expose screenshot/PDF/MHTML capture as optional CI evidence.
- It does not use virtual scroll or full-page scan for dynamic/news index pages.
- It does not use persistent sessions for sources that benefit from cookie/session continuity.
- It does not use Crawl4AI's fallback fetch hook as part of a collector ladder.
Conclusion: the Scout enhancement plan is feasible, but the first implementation is only a starting point. The next Scout work should move CI acquisition closer to Crawl4AI-native configuration instead of adding too much custom post-processing.
Implemented Slice On 2026-06-27
Implemented on the live Chowmes Scout service under /opt/prism/scout:
- Released Scout source/runtime as
0.1.1. - Updated Scout
pyproject.toml,scout/core/version.py,README.md,CHANGELOG.md, andscout/skill/scout.md. - Removed the exploratory
/ci/scrapeendpoint and its tests. - Kept
/scrapeas the single shared acquisition primitive. - Added backward-compatible opt-in request flags:
quality_analysiscleanupexpected_markersrecommend_collectorsource_id- Added explicit evidence fields to
ScrapeResponse: raw_markdownclean_markdownacquisition- Added
AcquisitionMetadataunderacquisitionwith schema aliasacquisition_metadata.v1. - Added explainable quality scoring with
quality_scoreandquality_reasons. - Added marker validation with
markers_found,markers_missing, andmarker_score. - Added collector recommendation metadata with
recommended_collectorandrecommended_collector_reason. - Added feed-like URL detection that recommends
rss_feedwithout parsing feeds inside Scout. - Added a benchmark CLI:
scout benchmark URL --output-dir DIR [--js/--no-js] [--expected-marker ...]
Benchmark runs write:
benchmark.json
comparison.md
direct_http.txt
scout_raw.md
scout_clean.md
samples/
Important implementation decision:
Crawl4AI-native remove_consent_popups and remove_overlay_elements were not enabled by default in this slice. During live exploration, enabling native cleanup created unacceptable latency on a simple page. The first slice therefore uses explicit post-processing cleanup and preserves raw evidence. Native cleanup must be reintroduced only after benchmarked source-by-source validation.
Enhancements To Add
1. Lock ci_acquisition.v1 response schema
Implementation status: implemented first slice.
Add CI-oriented profile behavior to the existing /scrape architecture with defaults optimized for competitive monitoring:
- raw markdown
- clean markdown
- link extraction
- word count and token estimate
- content hash
- boilerplate/consent cleanup
- cleanup rules applied
- source quality metadata
- quality score reasons
- extraction method metadata
- collector recommendation reasons
- duration and error metadata
Contract model:
scrape_response.v1 + acquisition_metadata.v1
The endpoint remains /scrape; only the optional response metadata is versioned.
Proposed opt-in request fields:
{
"quality_analysis": true,
"cleanup": true,
"expected_markers": ["AI Search", "Product updates"],
"recommend_collector": true
}
Endpoint:
POST /scrape
No separate CI endpoint is allowed.
Proposed response shape:
{
"success": true,
"url": "https://example.com",
"markdown": "current/default markdown",
"raw_markdown": "raw markdown when requested",
"clean_markdown": "clean markdown when requested",
"links": [],
"metadata": {},
"acquisition": {
"schema": "acquisition_metadata.v1",
"source_id": "optional-source-id",
"final_url": "https://example.com",
"status_code": 200,
"fetched_at": "2026-06-27T00:00:00Z",
"provider": "crawl4ai",
"content_hash": "...",
"boilerplate_removed": 0,
"cleanup_rules_applied": [],
"blocked": false,
"markers_found": [],
"markers_missing": [],
"marker_score": 1.0,
"quality_score": 0.82,
"quality_reasons": [],
"recommended_collector": "scout_scrape",
"recommended_collector_reason": "browser_rendered_product_page"
}
}
Field inventory:
successsource_idurlfinal_urlcanonical_urltitleraw_markdownclean_markdownlinksstatus_codefetched_atprovidercontent_hashword_counttoken_estimateduration_msboilerplate_removedcleanup_rules_appliedblockedmarkers_foundmarkers_missingmarker_scorequality_scorequality_reasonsrecommended_collectorrecommended_collector_reasonerror
Compatibility note:
The current implementation returns markdown. The schema lock should either rename this to clean_markdown or keep markdown as a backwards-compatible alias while adding explicit raw_markdown and clean_markdown.
Do not overload markdown fields confusingly:
markdownremains the existing/default field.raw_markdownis raw evidence when requested.clean_markdownis cleaned CI-ready content when requested.- acquisition-only fields live under
acquisition.
2. Consent and boilerplate cleanup
Implementation status: initial pattern-based cleanup now exists inside the shared /scrape path/profile. Broader benchmark against real competitor pages is still required.
Crawl4AI implication: test native remove_consent_popups, remove_overlay_elements, excluded_tags, and excluded_selector source-by-source before enabling. Live testing showed native popup/overlay cleanup can add too much latency when applied broadly.
Add reusable text filters for:
- cookie banners
- privacy preference text
- "accept all cookies"
- login/signup nav duplication
- repeated footer/nav blocks
- newsletter boilerplate
The cleanup must be opt-in or mode-specific at first so it does not damage product extraction use cases.
Auditability rule:
Cleanup must never destroy the only evidence. Scout should preserve raw markdown or a raw artifact, then return cleaned markdown with boilerplate_removed and cleanup_rules_applied.
3. Feed detection and handoff
Implementation status: feed-like URLs are detected and handed off with recommended_collector: rss_feed; true feed parsing remains to be built in the CI collector layer.
Scout should detect RSS/Atom/XML feeds and either:
- return
recommended_collector: rss_feed
This prevents massive markdown blobs like the OpenAI RSS result.
Boundary rule:
RSS/feed parsing should stay outside Scout for now. Scout can detect feeds and recommend rss_feed, but the CI runner owns feed parsing unless a future benchmark proves centralizing feed adapters inside Scout is better.
4. Extraction quality score
Implementation status: initial quality score implemented using text length, marker presence, title presence, blocked-page detection, and link extraction.
Crawl4AI implication: improve scoring with native diagnostics such as cleaned HTML length, fit-vs-raw markdown ratio, network/console capture on failures, screenshot evidence, and source-specific expected selectors.
Add a quality score to each scrape:
- enough text extracted
- expected markers present
- page title present
- blocked-page patterns absent
- consent ratio below threshold
- links extracted
This lets CI decide whether Scout output is reportable or needs fallback.
Quality score must be explainable. Add quality_reasons, for example:
[
"title_present",
"expected_markers_found",
"low_boilerplate_ratio",
"links_extracted"
]
The score should never be a black box.
5. Expected marker validation
Implementation status: initial marker validation implemented.
Allow callers to pass expected markers:
{
"url": "https://example.com",
"expected_markers": ["Product updates", "AI Search"]
}
Scout returns:
markers_foundmarkers_missingmarker_score
6. Collector benchmark harness
Implementation status: implemented first CLI artifact harness. Full six-source benchmark remains pending.
Crawl4AI implication: benchmark should compare direct HTTP, Scout basic scrape, Scout CI scrape with native cleanup, Scout screenshot evidence, and RSS/feed parsing.
Added a command, not an endpoint, to compare acquisition methods:
scout benchmark URL --output-dir DIR [--js/--no-js] [--expected-marker ...]
Minimum comparison dimensions:
- success
- duration
- character count
- word count
- marker score
- link count
- blocked status
- boilerplate ratio
- output sample
Benchmark output must be artifacted. Each run should write:
benchmark.json
comparison.md
direct_http.txt
scout_raw.md
scout_clean.md
samples/
Benchmark minimum source set:
- Google AI blog
- Constructor product page
- Coveo page
- Bloomreach page
- OpenAI RSS
- simple static page
7. CI source strategy export
Implementation status: not implemented. CI source strategy metadata has started in the CI runner, but Scout does not yet export source strategy patches.
Scout can recommend collector strategy:
rss_feedfor feedsdirect_httpfor simple static sourcesscout_scrapefor product/positioning/blog pagesmanual_onlyfor gated sources
But Scout should not own source configuration mutation. Patching sources.yaml belongs to the CI runner. Scout should output recommendation fields such as:
{
"recommended_collector": "rss_feed",
"recommended_collector_reason": "content_type_xml_feed"
}
The CI system decides whether to update source config.
Rollout Order
- Build benchmark harness. Done for CLI artifact harness.
- Run benchmark against the six target sources. Pending.
- Capture failures and gaps as Scout improvement tasks. Pending.
- Lock CI acquisition fields as a backward-compatible extension of the existing
/scrapecontract. Done for first slice. - Add Crawl4AI-native cleanup/options to
/scrape. Deferred until benchmarked because broad native cleanup caused latency in live testing. - Add raw and cleaned markdown separation. Done for opt-in profile.
- Add quality score reasons and collector recommendation reasons under
acquisition. Done for first slice. - Integrate CI runner client. Pending.
- Add source health records showing collector used and quality score. Pending.
- Rerun benchmark and compare before/after. Pending.
- Let the CI runner propose or patch source strategy config. Pending.
Verification Log
2026-06-27 release verification
Live Scout release:
docker compose -f docker/docker-compose.yml up -d --build scoutbuilt ascout-0.1.1wheel and restarted thescoutcontainer.docker psshowedscouthealthy on127.0.0.1:8421./healthreturnedstatus: ok, Scout0.1.1, Crawl4AI0.9.0.
Release contract checks:
- Default
POST /scrapeagainsthttps://example.comsucceeded in1348ms. - Default response stayed backward-compatible:
acquisition: nullraw_markdown: ""clean_markdown: ""- Opt-in
POST /scrapesucceeded in1189ms. - Opt-in response included:
schema: acquisition_metadata.v1quality_score: 1.0markers_found: ["Example Domain"]recommended_collector: direct_httprecommended_collector_reason: simple_static_pagePOST /ci/scrapereturned404.
Release benchmark:
scout benchmark https://example.com --output-dir /tmp/scout-release-011-benchmark --no-js --expected-marker "Example Domain"succeeded.- Artifacts created:
benchmark.jsoncomparison.mddirect_http.txtscout_raw.mdscout_clean.mdsamples/- Benchmark result:
- direct HTTP succeeded in
30ms - Scout scrape succeeded in
1239ms - recommendation:
direct_http - reason:
faster_static_page
Release test verification:
66 passed, 1 warning in 3.02s
The warning is a Starlette/httpx deprecation warning from FastAPI test client dependencies, not a Scout behavior failure.
Conclusion: Scout source-level enhancement is complete for this slice. The Competitive Intelligence workspace should now consume Scout 0.1.1 through /scrape and scout benchmark, not continue adding Scout features in this thread.
2026-06-27 implementation verification
Live Scout container:
docker psshowedscouthealthy on127.0.0.1:8421./healthreturnedstatus: ok, Scout0.1.0, Crawl4AI0.9.0.
Endpoint behavior:
- Default
POST /scrapeagainsthttps://example.comsucceeded in1332ms. - Default response kept compatibility:
acquisition: nullraw_markdown: ""clean_markdown: ""- Opt-in
POST /scrapewithquality_analysis,cleanup,expected_markers,recommend_collector, andsource_idsucceeded in1177ms. - Opt-in response included:
acquisition.schema: acquisition_metadata.v1source_id: smoke-examplecontent_hashmarkers_found: ["Example Domain"]marker_score: 1.0quality_score: 1.0recommended_collector: direct_httprecommended_collector_reason: simple_static_pagePOST /ci/scrapereturned404, confirming no bespoke CI endpoint is live.
Benchmark artifact verification:
scout benchmark https://example.com --output-dir /tmp/scout-benchmark-smoke --no-js --expected-marker "Example Domain"succeeded.- Artifacts created:
/tmp/scout-benchmark-smoke/benchmark.json/tmp/scout-benchmark-smoke/comparison.md/tmp/scout-benchmark-smoke/direct_http.txt/tmp/scout-benchmark-smoke/scout_raw.md/tmp/scout-benchmark-smoke/scout_clean.md/tmp/scout-benchmark-smoke/samples/- Benchmark result:
- direct HTTP succeeded in
39ms - Scout scrape succeeded in
1313ms - recommendation:
direct_http - reason:
faster_static_page
Test verification:
- Focused unit suite passed in the rebuilt container:
66 passed, 1 warning in 2.83s
The warning is a Starlette/httpx deprecation warning from FastAPI test client dependencies, not a Scout behavior failure.
Earlier exploration verification
Smoke-tested after rebuilding the live scout container on Chowmes:
/healthreturnedstatus: ok, Scout0.1.0, Crawl4AI0.7.7.- A separate
POST /ci/scraperoute was tested during exploration, then rejected as endpoint debt and removed from the accepted architecture. - Legacy
POST /scrapestill returned a successful scrape forhttps://example.com. - After the Crawl4AI audit,
/healthnow reports Crawl4AI0.9.0, matching the installed package reported bypip show. pyproject.tomlnow pinscrawl4ai==0.9.0rather than floating oncrawl4ai>=0.7.7.
Host-side Python compile passed for:
scout/core/types.pyscout/api/routers/ci.pyscout/api/main.pytests/unit/api/test_ci_scrape.py
Limitation: Scout unit tests could not be run on the VPS host because pytest is not installed outside the container. The endpoint was verified through live API smoke tests instead.
Acceptance Criteria
- Scout can be called securely from the CI runner.
/scraperejects missingX-API-Key.- Enhanced acquisition fields are opt-in or backward compatible.
- Response shape is documented as
scrape_response.v1 + acquisition_metadata.v1. - Scout output includes enough metadata to compare against direct HTTP.
- Acquisition metadata includes
content_hash,source_id,final_url,fetched_at,provider, and collector metadata. - Acquisition metadata is nested under
acquisitioninstead of cluttering the top-level scrape response. quality_scoreincludes explainablequality_reasons.- Collector recommendations include
recommended_collector_reason. - Cleanup never destroys raw evidence.
- Consent boilerplate is reduced on Constructor-like pages.
- RSS feeds are not treated as normal scrape pages.
- RSS/feed parsing stays in the CI runner unless later evidence argues for a Scout-owned feed adapter.
- CI can choose collector strategy by source type.
- Source health records which collector was used.
- Scout failures are visible as Scout improvement tasks, not hidden by fallback.
- Benchmark compares Scout and direct HTTP on the minimum benchmark source set.
- Benchmark outputs are saved as artifacts with raw, clean, direct, JSON, and markdown comparison files.
Relationship To Broader Scout
This plan is limited to Competitive Intelligence acquisition. It does not solve the broader Scout product/browser workbench.
Separate Scout work remains:
User Browser Capture -> DOM evidence -> product records -> Algolia preview
The CI acquisition profile should run in parallel conceptually, but should not sprawl into the larger Scout app/browser workflow.
Strategic Principle
Scout is Chowmes-owned infrastructure. Competitive Intelligence should use it aggressively where it creates advantage and should expose its weaknesses so Scout improves.