polyswarm_engine package reference
polyswarm_engine is a helper library for building PolySwarm Engines. It is designed to make it easy to:
- receive a bounty payload (artifact to analyze)
- fetch the artifact safely (bytes, stream, or temp file)
- return a correctly formatted analysis (verdict, bid, metadata)
- use common bidding helpers (min, max, rescale, NCT to wei)
This page is a practical overview of the parts most Engine partners use.
Core types
Bounty
A Bounty represents an incoming request to analyze an artifact. It includes the artifact type, where to download it, where to send your response, the expiration deadline, and bid rules.
Typical fields you will use:
artifact_type(example:FILEorURL)artifact_uri(where to fetch the artifact)response_uriorresponse_url(where to send your analysis)expiration(deadline)rules(includesmin_allowed_bid,max_allowed_bid)phase(example:assertionorarbitration)sha256,mimetype(commonly present for file artifacts)
Your analyzer function receives a Bounty as input.
Analysis
An Analysis is what your Engine returns. The minimum expected shape is:
verdict:malicious,benign,suspicious, orunknownbid: integer in NCT-weimetadata: optional object with extra context
Example:
return {
"verdict": ps.MALICIOUS,
"bid": ps.bid_max(bounty),
"metadata": {
"malware_family": "ExampleFamily",
"confidence": 0.92
}
}Engine registration
EngineManager
You typically register two functions:
@engine.register_head
Use this to attach static metadata once, then re-use it on every analysis.@engine.register_analyzer
This is your main scanning function. It runs once per bounty.
Example:
import polyswarm_engine as ps
engine = ps.EngineManager(name="my-engine", vendor="my-company")
@engine.register_head
def head() -> dict:
return {"scanner": {"version": "1.0.0"}}
@engine.register_analyzer
def analyze(bounty: ps.Bounty) -> ps.Analysis:
...Fetching artifacts
get_artifact_bytes(bounty)
Downloads the artifact and returns bytes. Best for small files or simple logic.
content = ps.get_artifact_bytes(bounty)get_artifact_stream(bounty)
Returns a stream-like object so you can forward the artifact to an external service without loading it all into memory.
stream = ps.get_artifact_stream(bounty)ArtifactTempfile(bounty)
Recommended for file-path tools, it downloads to a temp file and cleans up automatically.
with ps.ArtifactTempfile(bounty) as filepath:
run_my_scanner(filepath)Artifact type helpers
Use these to safely reject unsupported artifact types:
if not ps.is_file_artifact(bounty):
return ps.UNSUPPORTEDCommon helpers:
is_file_artifact(bounty)is_url_artifact(bounty)
Verdicts and bid rules
Use these verdict meanings consistently. Bid rules are enforced by the bounty bid range in the webhook payload (min_allowed_bid and max_allowed_bid).
MALICIOUS: strong detection, providemalware_familywhen possible
Bid must be withinmin_allowed_bidandmax_allowed_bid(bid cannot be0)BENIGN: strong evidence it is clean
Bid must be withinmin_allowed_bidandmax_allowed_bid(bid cannot be0)SUSPICIOUS: weak indicators, informational only
Bid must be 0UNKNOWN: unsupported, failed processing, timeouts, or low confidence
Bid must be 0
If you cannot justify a bid within the allowed range, return UNKNOWN instead.
Pre-built UNKNOWN responses
polyswarm_engine includes standard UNKNOWN responses for common cases:
ps.SKIPPEDps.ENCRYPTEDps.UNSAFE_DECOMPRESSIONps.UNSUPPORTEDps.CANNOT_FETCH
These are useful to avoid boilerplate and keep behaviour consistent.
Bidding helpers
Bids are integers in NCT-wei.
Useful helpers:
bid_min(bounty)bid_max(bounty)bid_range(bounty)bid_median(bounty)rescale_to_bid(bounty, value, min=0, max=100)to_wei(nct_amount)
Example, scale a confidence score into the bounty bid range:
score = 85
bid = ps.rescale_to_bid(bounty, score, min=0, max=100)Best practice summary
- return
202 Acceptedquickly at the webhook layer, scan in a worker - return
UNKNOWNfor unsupported types, failures, and timeouts - keep metadata stable and meaningful, avoid dumping raw tool strings
- keep bidding aligned with confidence, start conservative