Examples
These examples show how an Engine works end to end, from receiving a bounty to returning an analysis. Use them as references, then replace the analyzer logic with your own detection tooling.
Recommended learning path
If you are new to building a PolySwarm Engine, follow this order. Each page builds on the previous one:
- Quickstart: run the reference EICAR Engine locally and confirm you can return valid results
- Build your Engine: replace the template analyzer with your own detection logic
- Testing your Engine: run unit and local integration tests before marketplace testing
- Run your Engine as a webhook service: run the web server and worker so PolySwarm can deliver bounties
- End-to-end testing in the Development Community: validate real bounty flow in a safe environment
Once you complete the path above, use the examples below as patterns you can copy and adapt.
Example 1 - EICAR Engine (template)
Best for learning the basics and validating protocols.
The microengine-webhooks-py repository is the recommended starting point. It is a working Engine that detects EICAR and includes a web server, worker, and tests.
What it demonstrates:
- registering an analyzer (
@engine.register_analyzer) - fetching an artifact safely
- returning an Analysis (verdict, bid, metadata)
- handling unsupported artifact types safely (UNKNOWN)
Typical analyzer shape:
@engine.register_analyzer
def analyze(bounty: ps.Bounty) -> ps.Analysis:
if not ps.is_file_artifact(bounty):
return ps.UNSUPPORTED
content = ps.get_artifact_bytes(bounty)
if EICAR_STRING in content:
return {
"verdict": ps.MALICIOUS,
"bid": ps.bid_max(bounty),
"metadata": {"malware_family": "EICAR", "confidence": 1.0},
}
return {"verdict": ps.BENIGN, "bid": ps.bid_max(bounty), "metadata": {}}Quick local checks:
- empty bounties
- EICAR for file engines
- WICAR for URL engines
- unsupported types return UNKNOWN
Example 2 - External Scanner Integration Pattern (ClamAV style)
Best for integrating an existing scanner that expects file paths or runs as a service.
This pattern:
- downloads the artifact to a temp file
- runs a scanner tool
- maps tool output into verdict and metadata
Key ideas:
- enforce timeouts, treat timeouts as UNKNOWN
- keep malware family output stable and meaningful
- run scanning in a worker, not in the webhook request thread
Example pattern:
@engine.register_analyzer
def analyze(bounty: ps.Bounty) -> ps.Analysis:
if not ps.is_file_artifact(bounty):
return ps.UNSUPPORTED
with ps.ArtifactTempfile(bounty) as path:
result = scan_with_tool(path)
if result.malicious:
return {
"verdict": ps.MALICIOUS,
"bid": ps.bid_max(bounty),
"metadata": {"malware_family": result.family},
}
return {"verdict": ps.BENIGN, "bid": ps.bid_max(bounty)}Which example to start with
Use the EICAR template if you want:
- the fastest path to a working Engine
- a stable reference for protocols and expected behaviour
- a clear place to replace scanning logic (
analyze)
Use the external scanner pattern if you want:
- a model for integrating external tools safely
- a clean file-based workflow for CLI scanners
- a repeatable mapping from tool output to a stable verdict