[{"data":1,"prerenderedAt":2045},["ShallowReactive",2],{"page-\u002Fworkflows\u002Fquick-reference":3,"all-pages":1718},{"id":4,"title":5,"body":6,"description":1709,"extension":1710,"meta":1711,"navigation":95,"path":1712,"robots":1713,"seo":1714,"sitemap":1715,"stem":1716,"__hash__":1717},"content\u002F01.workflows\u002F00.quick-reference.md","Workflow Quick Reference",{"type":7,"value":8,"toc":1691},"minimark",[9,13,18,103,152,156,176,306,316,375,435,439,447,499,549,553,588,597,601,626,640,651,655,684,839,845,911,946,950,970,1006,1010,1066,1086,1102,1212,1216,1284,1336,1340,1402,1473,1477,1541,1611,1614,1644,1649,1653,1687],[10,11,12],"p",{},"This page is the machine-readable cheat sheet for the BHW workflow language.\nEvery snippet below is canonical syntax. Prefer these shapes when suggesting\nworkflow edits. Details live on the linked pages.",[14,15,17],"h2",{"id":16},"skeleton","Skeleton",[19,20,25],"pre",{"className":21,"code":22,"language":23,"meta":24,"style":24},"language-bhw shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","discover = activity(\n    name = \"discover\",\n    triggers = [trigger.cron(\"0 0 * * *\"), trigger.dispatch()],\n    steps = [\n        step.exec(\n            command = [\"subfinder\", \"-d\", config.var(\"target_domain\"), \"-o\", \"subs.txt\"],\n            id = \"enum\",\n        ),\n    ],\n)\n\nworkflow(name = \"recon\", activities = [discover])\n","bhw","",[26,27,28,36,42,48,54,60,66,72,78,84,90,97],"code",{"__ignoreMap":24},[29,30,33],"span",{"class":31,"line":32},"line",1,[29,34,35],{},"discover = activity(\n",[29,37,39],{"class":31,"line":38},2,[29,40,41],{},"    name = \"discover\",\n",[29,43,45],{"class":31,"line":44},3,[29,46,47],{},"    triggers = [trigger.cron(\"0 0 * * *\"), trigger.dispatch()],\n",[29,49,51],{"class":31,"line":50},4,[29,52,53],{},"    steps = [\n",[29,55,57],{"class":31,"line":56},5,[29,58,59],{},"        step.exec(\n",[29,61,63],{"class":31,"line":62},6,[29,64,65],{},"            command = [\"subfinder\", \"-d\", config.var(\"target_domain\"), \"-o\", \"subs.txt\"],\n",[29,67,69],{"class":31,"line":68},7,[29,70,71],{},"            id = \"enum\",\n",[29,73,75],{"class":31,"line":74},8,[29,76,77],{},"        ),\n",[29,79,81],{"class":31,"line":80},9,[29,82,83],{},"    ],\n",[29,85,87],{"class":31,"line":86},10,[29,88,89],{},")\n",[29,91,93],{"class":31,"line":92},11,[29,94,96],{"emptyLinePlaceholder":95},true,"\n",[29,98,100],{"class":31,"line":99},12,[29,101,102],{},"workflow(name = \"recon\", activities = [discover])\n",[104,105,106,118,142],"ul",{},[107,108,109,110,113,114,117],"li",{},"File must produce a ",[26,111,112],{},"workflow(...)"," value. Single-activity shorthand:\n",[26,115,116],{},"workflow(name = ..., triggers = [...], steps = [...])",".",[107,119,120,121,124,125,128,129,132,133,128,136,128,139,117],{},"Activities are wired by variable, not by ",[26,122,123],{},"name"," string:\n",[26,126,127],{},"trigger.on(discover.succeeded())",", ",[26,130,131],{},"discover.failed()",",\n",[26,134,135],{},"discover.completed()",[26,137,138],{},"discover.artifacts.\u003Cname>",[26,140,141],{},"discover.when(cond)",[107,143,144,145,128,148,151],{},"Events compose: ",[26,146,147],{},"event.all(a, b)",[26,149,150],{},"event.any(a, b)",", nestable.",[14,153,155],{"id":154},"step-identity-and-conditions","Step identity and conditions",[19,157,159],{"className":21,"code":158,"language":23,"meta":24,"style":24},"scan = step.exec(command = [\"nuclei\", \"-l\", \"live.txt\"], id = \"scan\", name = \"Nuclei scan\")\nrecheck = step.exec(command = [\"httpx\", \"-l\", \"live.txt\"]).when(scan.succeeded())\ncond = lambda run: run.steps.scan.conclusion == steps.Conclusion.SUCCEEDED\n",[26,160,161,166,171],{"__ignoreMap":24},[29,162,163],{"class":31,"line":32},[29,164,165],{},"scan = step.exec(command = [\"nuclei\", \"-l\", \"live.txt\"], id = \"scan\", name = \"Nuclei scan\")\n",[29,167,168],{"class":31,"line":38},[29,169,170],{},"recheck = step.exec(command = [\"httpx\", \"-l\", \"live.txt\"]).when(scan.succeeded())\n",[29,172,173],{"class":31,"line":44},[29,174,175],{},"cond = lambda run: run.steps.scan.conclusion == steps.Conclusion.SUCCEEDED\n",[104,177,178,202,233,255,276],{},[107,179,180,183,184,187,188,191,192,194,195,197,198,201],{},[26,181,182],{},"id"," is the machine key (",[26,185,186],{},"run.steps.\u003Cid>"," \u002F ",[26,189,190],{},"run.steps[\"\u003Cid>\"]","); ",[26,193,123],{}," is\nthe UI label. No ",[26,196,182],{}," means no stable ",[26,199,200],{},"run.steps"," key.",[107,203,204,207,208,211,212,215,216,218,219,222,223,187,226,229,230,117],{},[26,205,206],{},"run"," fields: ",[26,209,210],{},"run.ok"," (bool), ",[26,213,214],{},"run.inputs"," (dict), ",[26,217,200],{}," (dict of\n",[26,220,221],{},"step_result"," with ",[26,224,225],{},"status",[26,227,228],{},"conclusion","), ",[26,231,232],{},"run.trigger",[107,234,235,236,187,239,242,243,128,246,132,249,252,253,117],{},"Compare against ",[26,237,238],{},"steps.Status",[26,240,241],{},"steps.Conclusion"," (",[26,244,245],{},"SUCCEEDED",[26,247,248],{},"FAILED",[26,250,251],{},"SKIPPED","). Default condition is ",[26,254,210],{},[107,256,257,260,261,264,265,268,269,272,273,117],{},[26,258,259],{},".when(F)"," is the fluent form of ",[26,262,263],{},"cond = F","; ",[26,266,267],{},"F"," is a runtime predicate\n",[26,270,271],{},"run -> bool"," — a lambda or a step predicate such as ",[26,274,275],{},"scan.succeeded()",[107,277,278,279,128,281,128,283,128,286,128,289,292,293,296,297,299,300,302,303,305],{},"Most steps accept ",[26,280,182],{},[26,282,123],{},[26,284,285],{},"cond",[26,287,288],{},"allow_failure",[26,290,291],{},"timeout",".\n",[26,294,295],{},"step.spawn"," accepts ",[26,298,123],{}," and ",[26,301,291],{}," only; its ",[26,304,288],{},"\nparameter is accepted but ignored.",[14,307,309,312,313],{"id":308},"stepscript-vs-stepexec",[26,310,311],{},"step.script"," vs ",[26,314,315],{},"step.exec",[19,317,319],{"className":21,"code":318,"language":23,"meta":24,"style":24},"step.script(content = \"cat findings.txt | notify -provider slack\")\nstep.script(content = lambda run: \"subfinder -d {} -o subs.txt\".format(run.inputs[\"domain\"]))\nstep.exec(\n    command = [\"nuclei\", \"-l\", \"live.txt\", \"-severity\", config.var(\"nuclei_severity\")],\n    env = {\"GITHUB_TOKEN\": config.secret(\"github_token\")},\n    stdin = path.file(\"subs-clean.txt\"),\n    stdout = path.file(\"live.txt\"),\n    stderr = path.file(\"errors.log\"),\n    cwd = path.directory(\"workdir\"),\n    timeout = duration.minutes(30),\n)\n",[26,320,321,326,331,336,341,346,351,356,361,366,371],{"__ignoreMap":24},[29,322,323],{"class":31,"line":32},[29,324,325],{},"step.script(content = \"cat findings.txt | notify -provider slack\")\n",[29,327,328],{"class":31,"line":38},[29,329,330],{},"step.script(content = lambda run: \"subfinder -d {} -o subs.txt\".format(run.inputs[\"domain\"]))\n",[29,332,333],{"class":31,"line":44},[29,334,335],{},"step.exec(\n",[29,337,338],{"class":31,"line":50},[29,339,340],{},"    command = [\"nuclei\", \"-l\", \"live.txt\", \"-severity\", config.var(\"nuclei_severity\")],\n",[29,342,343],{"class":31,"line":56},[29,344,345],{},"    env = {\"GITHUB_TOKEN\": config.secret(\"github_token\")},\n",[29,347,348],{"class":31,"line":62},[29,349,350],{},"    stdin = path.file(\"subs-clean.txt\"),\n",[29,352,353],{"class":31,"line":68},[29,354,355],{},"    stdout = path.file(\"live.txt\"),\n",[29,357,358],{"class":31,"line":74},[29,359,360],{},"    stderr = path.file(\"errors.log\"),\n",[29,362,363],{"class":31,"line":80},[29,364,365],{},"    cwd = path.directory(\"workdir\"),\n",[29,367,368],{"class":31,"line":86},[29,369,370],{},"    timeout = duration.minutes(30),\n",[29,372,373],{"class":31,"line":92},[29,374,89],{},[104,376,377,395,425],{},[107,378,379,382,383,386,387,390,391,394],{},[26,380,381],{},"script"," = explicit shell (",[26,384,385],{},"shell = \"bash\""," default). ",[26,388,389],{},"exec"," = direct argv,\nno shell; ",[26,392,393],{},"command[0]"," is the program.",[107,396,397,399,400,403,404,403,407,410,411,414,415,410,418,421,422,117],{},[26,398,389],{}," receives exactly what is declared: no implicit env, stdin, or prior\nstdout. ",[26,401,402],{},"stdin","\u002F",[26,405,406],{},"stdout",[26,408,409],{},"stderr"," must be ",[26,412,413],{},"path.file(...)",";\n",[26,416,417],{},"cwd",[26,419,420],{},"path.directory(...)",". Non-zero exit fails unless\n",[26,423,424],{},"allow_failure = True",[107,426,427,430,431,434],{},[26,428,429],{},"command"," elements: strings, step-output paths, ",[26,432,433],{},"config.*"," refs, module\ninput refs, lazy expressions. Nested list = optional argv group (expands\nonly when all referenced optional module inputs are bound). Bare optional\nmodule input = dropped when unbound.",[14,436,438],{"id":437},"step-outputs","Step outputs",[10,440,441,442,117],{},"A step declares what it publishes; consumers use the step result, never the\nproducer's file name. See ",[443,444,446],"a",{"href":445},"\u002Fworkflows\u002Fstep-outputs","Step Outputs",[19,448,450],{"className":21,"code":449,"language":23,"meta":24,"style":24},"hosts = step.exec(\n    command = [\"subfinder\", \"-d\", config.var(\"target\")],\n    stdout = path.file(\"hosts.txt\"),\n)\nlive = step.exec(command = [\"httpx\", \"-l\", hosts.output], stdout = path.file(\"live.txt\"))\n\nscan = step.exec(\n    command = [\"nmap\", \"-sV\", \"-oA\", \"scan\", \"example.com\"],\n    outputs = {\"xml\": path.file(\"scan.xml\"), \"gnmap\": path.file(\"scan.gnmap\")},\n)\n",[26,451,452,457,462,467,471,476,480,485,490,495],{"__ignoreMap":24},[29,453,454],{"class":31,"line":32},[29,455,456],{},"hosts = step.exec(\n",[29,458,459],{"class":31,"line":38},[29,460,461],{},"    command = [\"subfinder\", \"-d\", config.var(\"target\")],\n",[29,463,464],{"class":31,"line":44},[29,465,466],{},"    stdout = path.file(\"hosts.txt\"),\n",[29,468,469],{"class":31,"line":50},[29,470,89],{},[29,472,473],{"class":31,"line":56},[29,474,475],{},"live = step.exec(command = [\"httpx\", \"-l\", hosts.output], stdout = path.file(\"live.txt\"))\n",[29,477,478],{"class":31,"line":62},[29,479,96],{"emptyLinePlaceholder":95},[29,481,482],{"class":31,"line":68},[29,483,484],{},"scan = step.exec(\n",[29,486,487],{"class":31,"line":74},[29,488,489],{},"    command = [\"nmap\", \"-sV\", \"-oA\", \"scan\", \"example.com\"],\n",[29,491,492],{"class":31,"line":80},[29,493,494],{},"    outputs = {\"xml\": path.file(\"scan.xml\"), \"gnmap\": path.file(\"scan.gnmap\")},\n",[29,496,497],{"class":31,"line":86},[29,498,89],{},[104,500,501,511,526,532,543],{},[107,502,503,506,507,510],{},[26,504,505],{},"run.output"," is the single declared output; ",[26,508,509],{},".outputs.\u003Cname>"," addresses\nseveral.",[107,512,513,128,516,519,520,523,524,117],{},[26,514,515],{},"stdout = path.file(...)",[26,517,518],{},"step.transform(destination = ...)"," and\n",[26,521,522],{},"step.agent(output = ...)"," expose that file as ",[26,525,505],{},[107,527,528,531],{},[26,529,530],{},"outputs = {...}"," declares files a tool writes itself; directory and glob\nvalues capture trees and sets.",[107,533,534,535,538,539,542],{},"Module outputs are read through the invocation, e.g.\n",[26,536,537],{},"scan.outputs.findings"," (or ",[26,540,541],{},"scan.output"," when the module declares one).",[107,544,545,548],{},[26,546,547],{},"workflow(isolated_steps = True)"," gives each data step its own private\nfilesystem; outputs are then the only data that crosses a step boundary.",[14,550,552],{"id":551},"durations","Durations",[19,554,556],{"className":21,"code":555,"language":23,"meta":24,"style":24},"duration.seconds(30)\nduration.milliseconds(500)\nduration.minutes(15)\nduration.hours(1).minutes(30)\nduration.days(7)\nduration.parse(\"2h45m\")\n",[26,557,558,563,568,573,578,583],{"__ignoreMap":24},[29,559,560],{"class":31,"line":32},[29,561,562],{},"duration.seconds(30)\n",[29,564,565],{"class":31,"line":38},[29,566,567],{},"duration.milliseconds(500)\n",[29,569,570],{"class":31,"line":44},[29,571,572],{},"duration.minutes(15)\n",[29,574,575],{"class":31,"line":50},[29,576,577],{},"duration.hours(1).minutes(30)\n",[29,579,580],{"class":31,"line":56},[29,581,582],{},"duration.days(7)\n",[29,584,585],{"class":31,"line":62},[29,586,587],{},"duration.parse(\"2h45m\")\n",[10,589,590,591,593,594,117],{},"Strictly positive. Used for activity\u002Fstep ",[26,592,291],{}," and artifact ",[26,595,596],{},"expires_in",[14,598,600],{"id":599},"dispatch-inputs","Dispatch inputs",[19,602,604],{"className":21,"code":603,"language":23,"meta":24,"style":24},"trigger.dispatch(inputs = {\n    \"domain\": input.string(required = True, description = \"Target domain\"),\n    \"aggressive\": input.bool(default = False, description = \"Aggressive mode\"),\n})\n",[26,605,606,611,616,621],{"__ignoreMap":24},[29,607,608],{"class":31,"line":32},[29,609,610],{},"trigger.dispatch(inputs = {\n",[29,612,613],{"class":31,"line":38},[29,614,615],{},"    \"domain\": input.string(required = True, description = \"Target domain\"),\n",[29,617,618],{"class":31,"line":44},[29,619,620],{},"    \"aggressive\": input.bool(default = False, description = \"Aggressive mode\"),\n",[29,622,623],{"class":31,"line":50},[29,624,625],{},"})\n",[10,627,628,629,187,632,635,636,639],{},"Dispatch inputs are ",[26,630,631],{},"input.string",[26,633,634],{},"input.bool"," only. There is no\n",[26,637,638],{},"input.file"," dispatch input.",[10,641,642,643,646,647,650],{},"Read at runtime as ",[26,644,645],{},"run.inputs[\"domain\"]"," (or\n",[26,648,649],{},"lambda run: ...run.inputs[\"domain\"]...",").",[14,652,654],{"id":653},"transforms","Transforms",[19,656,658],{"className":21,"code":657,"language":23,"meta":24,"style":24},"step.transform(\n    source = path.file(\"subs.txt\").lines(),\n    pipeline = transform.trim().lower().unique().sort(),\n    destination = path.file(\"subs-clean.txt\"),\n)\n",[26,659,660,665,670,675,680],{"__ignoreMap":24},[29,661,662],{"class":31,"line":32},[29,663,664],{},"step.transform(\n",[29,666,667],{"class":31,"line":38},[29,668,669],{},"    source = path.file(\"subs.txt\").lines(),\n",[29,671,672],{"class":31,"line":44},[29,673,674],{},"    pipeline = transform.trim().lower().unique().sort(),\n",[29,676,677],{"class":31,"line":50},[29,678,679],{},"    destination = path.file(\"subs-clean.txt\"),\n",[29,681,682],{"class":31,"line":56},[29,683,89],{},[104,685,686,726,747,771,787,798,827],{},[107,687,688,689,692,693,128,696,692,699,132,702,692,705,128,708,692,711,714,715,718,719,722,723,117],{},"Sources: ",[26,690,691],{},".lines()"," → ",[26,694,695],{},"Items\u003Cstring>",[26,697,698],{},".text()",[26,700,701],{},"string",[26,703,704],{},".json()",[26,706,707],{},"json",[26,709,710],{},".jsonl()",[26,712,713],{},"Items\u003Crecord>",". Bare ",[26,716,717],{},"path.file(\"x\")","\nwithout a parse is rejected (\"raw file\"). Explicit form:\n",[26,720,721],{},"source = path.file(\"x\")"," + ",[26,724,725],{},"pipeline = transform.lines()...",[107,727,728,729,128,732,128,735,128,738,132,741,128,744,117],{},"String ops (element-wise): ",[26,730,731],{},"trim",[26,733,734],{},"lower",[26,736,737],{},"upper",[26,739,740],{},"replace(from, to)",[26,742,743],{},"regex(pattern)",[26,745,746],{},"regex_replace(pattern, replacement)",[107,748,749,750,128,753,128,756,128,759,128,762,132,765,128,768,117],{},"Collection ops: ",[26,751,752],{},"unique",[26,754,755],{},"take(n)",[26,757,758],{},"drop(n)",[26,760,761],{},"sort",[26,763,764],{},"reverse",[26,766,767],{},"split(sep)",[26,769,770],{},"join(sep)",[107,772,773,774,777,778,132,781,132,784,117],{},"Lambda ops (deferred, lambda or named ",[26,775,776],{},"def","):\n",[26,779,780],{},"map(lambda h: \"{}:8080\".format(h))",[26,782,783],{},"filter(lambda row: row.severity == \"high\")",[26,785,786],{},"flat_map(lambda row: row.urls)",[107,788,789,790,403,792,403,794,797],{},"Memory model: element-wise\u002Fstreaming\u002Fstateful are streaming;\n",[26,791,761],{},[26,793,764],{},[26,795,796],{},"join"," buffer the whole sequence.",[107,799,800,801,187,804,807,808,811,812,815,816,819,820,823,824,117],{},"Partitioning (terminal; only ",[26,802,803],{},"partition.count(n)",[26,805,806],{},"partition.items(n)",",\nbare ints rejected):\n",[26,809,810],{},"transform.trim().unique().partition(partition.items(500))"," with\n",[26,813,814],{},"destination = path.file(\"batch-{partition_seq}.txt\")",". Partitioned output\nrequires ",[26,817,818],{},"{partition_seq}","; non-partitioned forbids it. Result types as\n",[26,821,822],{},"Items\u003CBatch\u003CT>>","; materialize with ",[26,825,826],{},"batch.as_file()",[107,828,829,830,128,833,128,836,117],{},"Records: ",[26,831,832],{},"row.field",[26,834,835],{},"row.host.lower()",[26,837,838],{},"row.urls[0]",[14,840,842],{"id":841},"stepfor_each",[26,843,844],{},"step.for_each",[19,846,848],{"className":21,"code":847,"language":23,"meta":24,"style":24},"step.for_each(\n    items = path.file(\"subs-clean.txt\").lines(),\n    do = lambda sub: [step.exec(command = [\"httpx\", \"-u\", sub])],\n    concurrency = 50,\n)\nstep.for_each(\n    items = path.glob(base = \"batches\", pattern = \"scan-*.txt\"),\n    do = probe,   # def probe(target): return [...]\n)\nstep.for_each(\n    items = path.file(\"live.txt\").lines().unique().partition(partition.count(20)),\n    do = lambda batch: [step.exec(command = [\"nuclei\", \"-l\", batch.as_file()])],\n)\n",[26,849,850,855,860,865,870,874,878,883,888,892,896,901,906],{"__ignoreMap":24},[29,851,852],{"class":31,"line":32},[29,853,854],{},"step.for_each(\n",[29,856,857],{"class":31,"line":38},[29,858,859],{},"    items = path.file(\"subs-clean.txt\").lines(),\n",[29,861,862],{"class":31,"line":44},[29,863,864],{},"    do = lambda sub: [step.exec(command = [\"httpx\", \"-u\", sub])],\n",[29,866,867],{"class":31,"line":50},[29,868,869],{},"    concurrency = 50,\n",[29,871,872],{"class":31,"line":56},[29,873,89],{},[29,875,876],{"class":31,"line":62},[29,877,854],{},[29,879,880],{"class":31,"line":68},[29,881,882],{},"    items = path.glob(base = \"batches\", pattern = \"scan-*.txt\"),\n",[29,884,885],{"class":31,"line":74},[29,886,887],{},"    do = probe,   # def probe(target): return [...]\n",[29,889,890],{"class":31,"line":80},[29,891,89],{},[29,893,894],{"class":31,"line":86},[29,895,854],{},[29,897,898],{"class":31,"line":92},[29,899,900],{},"    items = path.file(\"live.txt\").lines().unique().partition(partition.count(20)),\n",[29,902,903],{"class":31,"line":99},[29,904,905],{},"    do = lambda batch: [step.exec(command = [\"nuclei\", \"-l\", batch.as_file()])],\n",[29,907,909],{"class":31,"line":908},13,[29,910,89],{},[104,912,913,927,933,943],{},[107,914,915,918,919,922,923,926],{},[26,916,917],{},"items",": list, ",[26,920,921],{},"path.glob(base, pattern)",", or any ",[26,924,925],{},"Items\u003CT>"," expression.",[107,928,929,932],{},[26,930,931],{},"do",": one-parameter function, deferred per item; no magic variable.",[107,934,935,938,939,942],{},[26,936,937],{},"Batch\u003CT>"," is execution-local, not a file — call ",[26,940,941],{},".as_file()"," for tools.",[107,944,945],{},"Concurrency guide: CPU-bound ~5, network probes ~50, aggressive scanners\nmoderate.",[14,947,949],{"id":948},"concurrency","Concurrency",[19,951,953],{"className":21,"code":952,"language":23,"meta":24,"style":24},"step.parallel([[step.exec(command = [\"subfinder\", ...])], [step.exec(command = [\"naabu\", ...])]])\nhandle = step.spawn([step.exec(command = [\"naabu\", \"-p\", \"-\", ...])])\nstep.join([handle])\n",[26,954,955,960,965],{"__ignoreMap":24},[29,956,957],{"class":31,"line":32},[29,958,959],{},"step.parallel([[step.exec(command = [\"subfinder\", ...])], [step.exec(command = [\"naabu\", ...])]])\n",[29,961,962],{"class":31,"line":38},[29,963,964],{},"handle = step.spawn([step.exec(command = [\"naabu\", \"-p\", \"-\", ...])])\n",[29,966,967],{"class":31,"line":44},[29,968,969],{},"step.join([handle])\n",[104,971,972,987],{},[107,973,974,977,978,981,982,403,984,986],{},[26,975,976],{},"parallel"," takes an outer list of branches (each an inner sequential list);\nflat lists rejected; ",[26,979,980],{},"parallel([])"," is a no-op. Fails if any branch fails;\nsiblings are never cancelled. ",[26,983,285],{},[26,985,288],{}," allowed on the barrier.",[107,988,989,992,993,995,996,296,998,299,1000,1002,1003,1005],{},[26,990,991],{},"spawn"," returns a handle (sync reference, not data); ",[26,994,796],{}," blocks until all\nsucceed. ",[26,997,295],{},[26,999,123],{},[26,1001,291],{},"; its ",[26,1004,288],{},"\nparameter is accepted but ignored. Handles never merge data — share files via workspace\u002Fartifacts.",[14,1007,1009],{"id":1008},"modules","Modules",[19,1011,1013],{"className":21,"code":1012,"language":23,"meta":24,"style":24},"domain = input.string(name = \"domain\", description = \"Root domain\")\nsubs = output.file(name = \"subs\", description = \"Validated subdomains\")\n\nmodule(\n    inputs = [domain],\n    outputs = [subs],\n    steps = [\n        step.exec(command = [\"subfinder\", \"-d\", domain, \"-o\", \"subs.txt\"]),\n        step.output(subs, path = path.file(\"subs.txt\")),\n    ],\n)\n",[26,1014,1015,1020,1025,1029,1034,1039,1044,1048,1053,1058,1062],{"__ignoreMap":24},[29,1016,1017],{"class":31,"line":32},[29,1018,1019],{},"domain = input.string(name = \"domain\", description = \"Root domain\")\n",[29,1021,1022],{"class":31,"line":38},[29,1023,1024],{},"subs = output.file(name = \"subs\", description = \"Validated subdomains\")\n",[29,1026,1027],{"class":31,"line":44},[29,1028,96],{"emptyLinePlaceholder":95},[29,1030,1031],{"class":31,"line":50},[29,1032,1033],{},"module(\n",[29,1035,1036],{"class":31,"line":56},[29,1037,1038],{},"    inputs = [domain],\n",[29,1040,1041],{"class":31,"line":62},[29,1042,1043],{},"    outputs = [subs],\n",[29,1045,1046],{"class":31,"line":68},[29,1047,53],{},[29,1049,1050],{"class":31,"line":74},[29,1051,1052],{},"        step.exec(command = [\"subfinder\", \"-d\", domain, \"-o\", \"subs.txt\"]),\n",[29,1054,1055],{"class":31,"line":80},[29,1056,1057],{},"        step.output(subs, path = path.file(\"subs.txt\")),\n",[29,1059,1060],{"class":31,"line":86},[29,1061,83],{},[29,1063,1064],{"class":31,"line":92},[29,1065,89],{},[19,1067,1069],{"className":21,"code":1068,"language":23,"meta":24,"style":24},"load(\"yourname\u002Fsubdomain-enum\", \"subdomain_enum\")\nenum_run = step.module(subdomain_enum, inputs = {\"domain\": config.var(\"target_domain\")})\nstep.exec(command = [\"nuclei\", \"-l\", enum_run.outputs.subs])\n",[26,1070,1071,1076,1081],{"__ignoreMap":24},[29,1072,1073],{"class":31,"line":32},[29,1074,1075],{},"load(\"yourname\u002Fsubdomain-enum\", \"subdomain_enum\")\n",[29,1077,1078],{"class":31,"line":38},[29,1079,1080],{},"enum_run = step.module(subdomain_enum, inputs = {\"domain\": config.var(\"target_domain\")})\n",[29,1082,1083],{"class":31,"line":44},[29,1084,1085],{},"step.exec(command = [\"nuclei\", \"-l\", enum_run.outputs.subs])\n",[10,1087,1088,1091,1092,1095,1096,1099,1100,117],{},[26,1089,1090],{},"step.module"," only invokes modules imported with ",[26,1093,1094],{},"load()"," from the module\nregistry. A local ",[26,1097,1098],{},"module(...)"," value defined in the same file cannot be\npassed to ",[26,1101,1090],{},[104,1103,1104,1141,1161,1185],{},[107,1105,1106,1107,1111,1112,1115,1116,1118,1119,1122,1123,1126,1127,1129,1130,1133,1134,1137,1138,117],{},"Module outputs are read through the ",[1108,1109,1110],"strong",{},"invocation value"," using a declared\noutput name: ",[26,1113,1114],{},"enum_run.outputs.subs",". A ",[26,1117,1094],{}," symbol is the module\ndefinition, not an invocation, and has no ",[26,1120,1121],{},".outputs","; bind the invocation\nfirst (",[26,1124,1125],{},"enum_run = step.module(...)","). Outputs are file references, usable as\nmodule inputs, ",[26,1128,315],{}," argv elements, and ",[26,1131,1132],{},"artifact_entry(source = ...)","\nsources. They are not ",[26,1135,1136],{},"\u003Cactivity>.artifacts.\u003Cname>","; that namespace only\nexists after ",[26,1139,1140],{},"step.upload_artifact",[107,1142,1143,1144,1147,1148,403,1151,1154,1155,1158,1159,117],{},"A module runs in an ",[1108,1145,1146],{},"isolated workspace",": its ",[26,1149,1150],{},"file",[26,1152,1153],{},"directory"," inputs\nare copied in, it cannot read the caller's other files, and only its declared\noutputs are copied back (as ",[26,1156,1157],{},"\u003Cmodule-path>.\u003Cname>","). Never read a producer's\ninternal file name; use the invocation's ",[26,1160,509],{},[107,1162,1163,1166,1167,1170,1171,1174,1175,403,1178,1181,1182,117],{},[26,1164,1165],{},"input.string\u002Fbool\u002Ffile\u002Fdirectory(name, ...)"," are public refs; ",[26,1168,1169],{},"output.file","\nlikewise. ",[26,1172,1173],{},"input.string(..., secret = True)"," marks a credential, and callers\nbind string inputs from literals or ",[26,1176,1177],{},"config.var(...)",[26,1179,1180],{},"config.secret(...)",".\nEach declared output assigned exactly once via ",[26,1183,1184],{},"step.output",[107,1186,1187,1188,403,1191,1194,1195,128,1198,128,1201,1204,1205,1208,1209,117],{},"Module files compile in module mode: no ",[26,1189,1190],{},"workflow",[26,1192,1193],{},"activity"," globals and no\nproject-context namespaces (",[26,1196,1197],{},"config",[26,1199,1200],{},"dataset",[26,1202,1203],{},"mcp","). Modules are\nself-contained and bind such values through their declared inputs; agent\nsteps stay available (",[26,1206,1207],{},"provider.key",") but are explicit parameters.\nUnbound optional inputs use their ",[26,1210,1211],{},"default",[14,1213,1215],{"id":1214},"agents","Agents",[19,1217,1219],{"className":21,"code":1218,"language":23,"meta":24,"style":24},"step.agent(\n    prompt = \"Classify each finding as EXPLOITABLE, LIKELY_NOISE, or OUT_OF_SCOPE.\",\n    provider = provider.key(\"anthropic\u002Fpersonal\"),\n    model = model(\"default\"),\n    context = [\n        agent.context.path(description = \"Findings to triage.\", path = path.file(\"findings.txt\")),\n        agent.context.text(description = \"Target domain.\", value = config.var(\"target_domain\")),\n        agent.context.artifact(description = \"Prior results.\", artifact = scan.artifacts.findings),\n        agent.context.dataset(description = \"Known hosts.\", dataset = dataset.table(\"subdomains\")),\n    ],\n    tools = [tool.shell(), mcp.server(\"github\")],\n    output = agent.output(path = path.file(\"agent-output.txt\")),\n)\n",[26,1220,1221,1226,1231,1236,1241,1246,1251,1256,1261,1266,1270,1275,1280],{"__ignoreMap":24},[29,1222,1223],{"class":31,"line":32},[29,1224,1225],{},"step.agent(\n",[29,1227,1228],{"class":31,"line":38},[29,1229,1230],{},"    prompt = \"Classify each finding as EXPLOITABLE, LIKELY_NOISE, or OUT_OF_SCOPE.\",\n",[29,1232,1233],{"class":31,"line":44},[29,1234,1235],{},"    provider = provider.key(\"anthropic\u002Fpersonal\"),\n",[29,1237,1238],{"class":31,"line":50},[29,1239,1240],{},"    model = model(\"default\"),\n",[29,1242,1243],{"class":31,"line":56},[29,1244,1245],{},"    context = [\n",[29,1247,1248],{"class":31,"line":62},[29,1249,1250],{},"        agent.context.path(description = \"Findings to triage.\", path = path.file(\"findings.txt\")),\n",[29,1252,1253],{"class":31,"line":68},[29,1254,1255],{},"        agent.context.text(description = \"Target domain.\", value = config.var(\"target_domain\")),\n",[29,1257,1258],{"class":31,"line":74},[29,1259,1260],{},"        agent.context.artifact(description = \"Prior results.\", artifact = scan.artifacts.findings),\n",[29,1262,1263],{"class":31,"line":80},[29,1264,1265],{},"        agent.context.dataset(description = \"Known hosts.\", dataset = dataset.table(\"subdomains\")),\n",[29,1267,1268],{"class":31,"line":86},[29,1269,83],{},[29,1271,1272],{"class":31,"line":92},[29,1273,1274],{},"    tools = [tool.shell(), mcp.server(\"github\")],\n",[29,1276,1277],{"class":31,"line":99},[29,1278,1279],{},"    output = agent.output(path = path.file(\"agent-output.txt\")),\n",[29,1281,1282],{"class":31,"line":908},[29,1283,89],{},[104,1285,1286,1300,1323],{},[107,1287,1288,1291,1292,1295,1296,1299],{},[26,1289,1290],{},"provider"," is required and must be enabled for the project\n(",[26,1293,1294],{},"unknown_provider_key"," otherwise). ",[26,1297,1298],{},"model"," is optional.",[107,1301,1302,1305,1306,1309,1310,128,1313,132,1316,128,1319,1322],{},[26,1303,1304],{},"context"," is a list of ",[26,1307,1308],{},"agent.context.*"," (dict form rejected):\n",[26,1311,1312],{},"text(description, value)",[26,1314,1315],{},"path(description, path)",[26,1317,1318],{},"artifact(description, artifact)",[26,1320,1321],{},"dataset(description, dataset)",".\nResources pass by reference, never injected wholesale.",[107,1324,1325,1328,1329,128,1332,1335],{},[26,1326,1327],{},"tools",": ",[26,1330,1331],{},"tool.shell()",[26,1333,1334],{},"mcp.server(\"name\")"," (preconfigured connections).\nOutput defaults to free-form text.",[14,1337,1339],{"id":1338},"datasets","Datasets",[19,1341,1343],{"className":21,"code":1342,"language":23,"meta":24,"style":24},"step.update_dataset(\n    table = \"subdomains\",\n    source = path.file(\"subs-clean.txt\").lines(),\n    pipeline = transform.unique(),\n    mapping = {\"host\": row.value, \"source\": \"subfinder\"},\n    mode = \"upsert\",\n)\nstep.download_dataset(\n    table = \"subdomains\",\n    destination = path.file(\"known.csv\"),\n    format = \"csv\",\n)\n",[26,1344,1345,1350,1355,1360,1365,1370,1375,1379,1384,1388,1393,1398],{"__ignoreMap":24},[29,1346,1347],{"class":31,"line":32},[29,1348,1349],{},"step.update_dataset(\n",[29,1351,1352],{"class":31,"line":38},[29,1353,1354],{},"    table = \"subdomains\",\n",[29,1356,1357],{"class":31,"line":44},[29,1358,1359],{},"    source = path.file(\"subs-clean.txt\").lines(),\n",[29,1361,1362],{"class":31,"line":50},[29,1363,1364],{},"    pipeline = transform.unique(),\n",[29,1366,1367],{"class":31,"line":56},[29,1368,1369],{},"    mapping = {\"host\": row.value, \"source\": \"subfinder\"},\n",[29,1371,1372],{"class":31,"line":62},[29,1373,1374],{},"    mode = \"upsert\",\n",[29,1376,1377],{"class":31,"line":68},[29,1378,89],{},[29,1380,1381],{"class":31,"line":74},[29,1382,1383],{},"step.download_dataset(\n",[29,1385,1386],{"class":31,"line":80},[29,1387,1354],{},[29,1389,1390],{"class":31,"line":86},[29,1391,1392],{},"    destination = path.file(\"known.csv\"),\n",[29,1394,1395],{"class":31,"line":92},[29,1396,1397],{},"    format = \"csv\",\n",[29,1399,1400],{"class":31,"line":99},[29,1401,89],{},[104,1403,1404,1428,1447],{},[107,1405,1406,1409,1410,242,1413,1416,1417,1419,1420,1423,1424,1427],{},[26,1407,1408],{},"mapping"," keys are columns; values evaluate against ",[26,1411,1412],{},"row",[26,1414,1415],{},"row.value"," for\nlines, ",[26,1418,832],{}," for JSONL). ",[26,1421,1422],{},"table"," names an existing project table (or\n",[26,1425,1426],{},"dataset.table(\"name\")"," reference elsewhere).",[107,1429,1430,1433,1434,1437,1438,403,1441,1444,1445,117],{},[26,1431,1432],{},"step.download_dataset"," exports the dataset's current logical state into the\nworkspace (",[26,1435,1436],{},"\"csv\""," default, or ",[26,1439,1440],{},"\"jsonl\"",[26,1442,1443],{},"\"json\"","); the step exposes it as\n",[26,1446,505],{},[107,1448,1449,1452,1453,1456,1457,1328,1460,1462,1463,1465,1466,187,1469,1472],{},[26,1450,1451],{},"mode"," is the string ",[26,1454,1455],{},"\"upsert\""," or ",[26,1458,1459],{},"\"sync\"",[26,1461,1455],{}," accumulates;\n",[26,1464,1459],{}," marks absent identities stale. Identity\u002Freconciliation owned by\nthe dataset service. The ",[26,1467,1468],{},"dataset.upsert()",[26,1470,1471],{},"dataset.sync()"," values are\nnot accepted here.",[14,1474,1476],{"id":1475},"decisions","Decisions",[19,1478,1480],{"className":21,"code":1479,"language":23,"meta":24,"style":24},"step.decision(\n    state = path.file(\"findings.json\"),\n    questions = {\n        \"relevant\": decision.noul(\"Is this finding relevant?\"),\n        \"severity\": decision.choice(\"Severity?\", options = [\"low\", \"medium\", \"high\"]),\n        \"priority\": decision.score(\"Priority?\", min = 0, max = 3),\n    },\n    provider = \"jevos\",\n    endpoint = config.var(\"jevos_endpoint\"),\n    api_key = config.secret(\"jevos_api_key\"),\n    output = path.file(\"decision.json\"),\n)\n",[26,1481,1482,1487,1492,1497,1502,1507,1512,1517,1522,1527,1532,1537],{"__ignoreMap":24},[29,1483,1484],{"class":31,"line":32},[29,1485,1486],{},"step.decision(\n",[29,1488,1489],{"class":31,"line":38},[29,1490,1491],{},"    state = path.file(\"findings.json\"),\n",[29,1493,1494],{"class":31,"line":44},[29,1495,1496],{},"    questions = {\n",[29,1498,1499],{"class":31,"line":50},[29,1500,1501],{},"        \"relevant\": decision.noul(\"Is this finding relevant?\"),\n",[29,1503,1504],{"class":31,"line":56},[29,1505,1506],{},"        \"severity\": decision.choice(\"Severity?\", options = [\"low\", \"medium\", \"high\"]),\n",[29,1508,1509],{"class":31,"line":62},[29,1510,1511],{},"        \"priority\": decision.score(\"Priority?\", min = 0, max = 3),\n",[29,1513,1514],{"class":31,"line":68},[29,1515,1516],{},"    },\n",[29,1518,1519],{"class":31,"line":74},[29,1520,1521],{},"    provider = \"jevos\",\n",[29,1523,1524],{"class":31,"line":80},[29,1525,1526],{},"    endpoint = config.var(\"jevos_endpoint\"),\n",[29,1528,1529],{"class":31,"line":86},[29,1530,1531],{},"    api_key = config.secret(\"jevos_api_key\"),\n",[29,1533,1534],{"class":31,"line":92},[29,1535,1536],{},"    output = path.file(\"decision.json\"),\n",[29,1538,1539],{"class":31,"line":99},[29,1540,89],{},[104,1542,1543,1558,1589,1600],{},[107,1544,1545,1546,1549,1550,1553,1554,1557],{},"Question types: ",[26,1547,1548],{},"decision.noul(question)"," (binary, optional confidence),\n",[26,1551,1552],{},"decision.choice(question, options = [...])"," (one of a fixed set),\n",[26,1555,1556],{},"decision.score(question, min, max)"," (bounded integer).",[107,1559,1560,1562,1563,1566,1567,1570,1571,1574,1575,403,1577,403,1579,1582,1583,1585,1586,1588],{},[26,1561,1290],{}," is optional and selects the implementation: ",[26,1564,1565],{},"\"jevos\""," (the\ndefault, the built-in live jevos decision server reached at ",[26,1568,1569],{},"endpoint",") or\n",[26,1572,1573],{},"\"mock\""," (deterministic, no network, for tests). Any other name is rejected.\n",[26,1576,1569],{},[26,1578,1298],{},[26,1580,1581],{},"api_key"," are optional and resolved at execution time;\n",[26,1584,1581],{}," must be a ",[26,1587,1180],{}," reference.",[107,1590,1591,1592,1595,1596,1599],{},"jevos limits: a ",[26,1593,1594],{},"choice"," needs 2–26 options and a ",[26,1597,1598],{},"score"," needs 2–10 levels.",[107,1601,1602,1603,1606,1607,1610],{},"The result is written to ",[26,1604,1605],{},"output"," as a typed JSON document keyed by question\nname. It is model-produced data, not proof: answers are validated against the\ndeclared questions before the result is written, and a self-reported\n",[26,1608,1609],{},"probability"," is not a calibrated probability.",[14,1612,1613],{"id":1197},"Config",[19,1615,1617],{"className":21,"code":1616,"language":23,"meta":24,"style":24},"config.var(\"target_domain\")\nconfig.secret(\"github_token\")\nconfig.mcp(\"github\")\n\"https:\u002F\u002F\" + config.var(\"target_domain\")\nconfig.var(\"target_domain\").trim()\n",[26,1618,1619,1624,1629,1634,1639],{"__ignoreMap":24},[29,1620,1621],{"class":31,"line":32},[29,1622,1623],{},"config.var(\"target_domain\")\n",[29,1625,1626],{"class":31,"line":38},[29,1627,1628],{},"config.secret(\"github_token\")\n",[29,1630,1631],{"class":31,"line":44},[29,1632,1633],{},"config.mcp(\"github\")\n",[29,1635,1636],{"class":31,"line":50},[29,1637,1638],{},"\"https:\u002F\u002F\" + config.var(\"target_domain\")\n",[29,1640,1641],{"class":31,"line":56},[29,1642,1643],{},"config.var(\"target_domain\").trim()\n",[104,1645,1646],{},[107,1647,1648],{},"References only; resolved at execution time, never serialized. Secrets stay\nsensitive through concat\u002Ftrim\u002Fcasing. Scope\n(global\u002Forg\u002Fproject\u002Fenvironment) hidden from the DSL.",[14,1650,1652],{"id":1651},"artifacts-and-blobs","Artifacts and blobs",[19,1654,1656],{"className":21,"code":1655,"language":23,"meta":24,"style":24},"step.upload_artifact(\n    name = \"subdomains\",\n    expires_in = duration.days(7),\n    entries = [artifact_entry(source = \"subs.txt\", destination = \"subs.txt\")],\n)\nstep.download_artifact(discover.artifacts.subdomains)\n",[26,1657,1658,1663,1668,1673,1678,1682],{"__ignoreMap":24},[29,1659,1660],{"class":31,"line":32},[29,1661,1662],{},"step.upload_artifact(\n",[29,1664,1665],{"class":31,"line":38},[29,1666,1667],{},"    name = \"subdomains\",\n",[29,1669,1670],{"class":31,"line":44},[29,1671,1672],{},"    expires_in = duration.days(7),\n",[29,1674,1675],{"class":31,"line":50},[29,1676,1677],{},"    entries = [artifact_entry(source = \"subs.txt\", destination = \"subs.txt\")],\n",[29,1679,1680],{"class":31,"line":56},[29,1681,89],{},[29,1683,1684],{"class":31,"line":62},[29,1685,1686],{},"step.download_artifact(discover.artifacts.subdomains)\n",[1688,1689,1690],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":24,"searchDepth":56,"depth":50,"links":1692},[1693,1694,1695,1697,1698,1699,1700,1701,1702,1703,1704,1705,1706,1707,1708],{"id":16,"depth":38,"text":17},{"id":154,"depth":38,"text":155},{"id":308,"depth":38,"text":1696},"step.script vs step.exec",{"id":437,"depth":38,"text":438},{"id":551,"depth":38,"text":552},{"id":599,"depth":38,"text":600},{"id":653,"depth":38,"text":654},{"id":841,"depth":38,"text":844},{"id":948,"depth":38,"text":949},{"id":1008,"depth":38,"text":1009},{"id":1214,"depth":38,"text":1215},{"id":1338,"depth":38,"text":1339},{"id":1475,"depth":38,"text":1476},{"id":1197,"depth":38,"text":1613},{"id":1651,"depth":38,"text":1652},"Copy-paste BHW patterns for AI assistants and humans: workflow skeleton, steps, transforms, fan-out, modules, agents, datasets, decisions, and config.","md",{},"\u002Fworkflows\u002Fquick-reference",null,{"title":5,"description":1709},{"loc":1712},"01.workflows\u002F00.quick-reference","mDkWQ6fryIZtDhJNRCYeeynZLzsh_UgnwB-Kh5racpo",[1719,1772,1788,1807,1841,1857,1869,1880,1891,1902,1926,1945,1965,1976,1987],{"title":1720,"path":1721,"stem":1722,"children":1723},"Workflows","\u002Fworkflows","01.workflows",[1724,1726,1727,1731,1735,1739,1741,1744,1747,1751,1754,1757,1760,1764,1768],{"title":1720,"path":1721,"stem":1725},"01.workflows\u002Findex",{"title":5,"path":1712,"stem":1716},{"title":1728,"path":1729,"stem":1730},"Workflows Overview","\u002Fworkflows\u002Foverview","01.workflows\u002F01.overview",{"title":1732,"path":1733,"stem":1734},"Workflow Syntax Reference","\u002Fworkflows\u002Fsyntax-reference","01.workflows\u002F02.syntax-reference",{"title":1736,"path":1737,"stem":1738},"Steps","\u002Fworkflows\u002Fsteps","01.workflows\u002F03.steps",{"title":446,"path":445,"stem":1740},"01.workflows\u002F04.step-outputs",{"title":949,"path":1742,"stem":1743},"\u002Fworkflows\u002Fconcurrency","01.workflows\u002F05.concurrency",{"title":654,"path":1745,"stem":1746},"\u002Fworkflows\u002Ftransforms","01.workflows\u002F06.transforms",{"title":1748,"path":1749,"stem":1750},"For Each","\u002Fworkflows\u002Ffor-each","01.workflows\u002F07.for-each",{"title":1009,"path":1752,"stem":1753},"\u002Fworkflows\u002Fmodules","01.workflows\u002F08.modules",{"title":1215,"path":1755,"stem":1756},"\u002Fworkflows\u002Fagents","01.workflows\u002F09.agents",{"title":1476,"path":1758,"stem":1759},"\u002Fworkflows\u002Fdecisions","01.workflows\u002F10.decisions",{"title":1761,"path":1762,"stem":1763},"Configuration References","\u002Fworkflows\u002Fconfig","01.workflows\u002F11.config",{"title":1765,"path":1766,"stem":1767},"Comparison With Other Automation Systems","\u002Fworkflows\u002Fcomparison","01.workflows\u002F12.comparison",{"title":1769,"path":1770,"stem":1771},"Generate with AI","\u002Fworkflows\u002Fai-generation","01.workflows\u002F13.ai-generation",{"title":1773,"path":1774,"stem":1775,"children":1776},"Projects","\u002Fprojects","02.projects",[1777,1780,1784],{"title":1778,"path":1774,"stem":1779},"Projects & Runs","02.projects\u002Findex",{"title":1781,"path":1782,"stem":1783},"Projects Overview","\u002Fprojects\u002Foverview","02.projects\u002F1.overview",{"title":1785,"path":1786,"stem":1787},"Runs & Artifacts","\u002Fprojects\u002Fruns-artifacts","02.projects\u002F2.runs-artifacts",{"title":1789,"path":1790,"stem":1791,"children":1792},"Runners","\u002Frunners","03.runners",[1793,1795,1799,1803],{"title":1789,"path":1790,"stem":1794},"03.runners\u002Findex",{"title":1796,"path":1797,"stem":1798},"Runner Overview","\u002Frunners\u002Foverview","03.runners\u002F1.overview",{"title":1800,"path":1801,"stem":1802},"Getting Started with Runners","\u002Frunners\u002Fgetting-started","03.runners\u002F2.getting-started",{"title":1804,"path":1805,"stem":1806},"Custom Runner Images","\u002Frunners\u002Fcustom-image","03.runners\u002F3.custom-image",{"title":1339,"path":1808,"stem":1809,"children":1810},"\u002Fdatasets","04.datasets",[1811,1813,1817,1821,1825,1829,1833,1837],{"title":1339,"path":1808,"stem":1812},"04.datasets\u002Findex",{"title":1814,"path":1815,"stem":1816},"Datasets Overview","\u002Fdatasets\u002Foverview","04.datasets\u002F1.overview",{"title":1818,"path":1819,"stem":1820},"Dataset Schemas and Identity","\u002Fdatasets\u002Fschema","04.datasets\u002F2.schema",{"title":1822,"path":1823,"stem":1824},"Pushing and Reading Dataset Rows","\u002Fdatasets\u002Fworkflows","04.datasets\u002F3.workflows",{"title":1826,"path":1827,"stem":1828},"Dataset SQL Reference","\u002Fdatasets\u002Fsql","04.datasets\u002F4.sql",{"title":1830,"path":1831,"stem":1832},"Dataset Structured Filters","\u002Fdatasets\u002Ffilters","04.datasets\u002F5.filters",{"title":1834,"path":1835,"stem":1836},"Dataset Saved Views","\u002Fdatasets\u002Fviews","04.datasets\u002F6.views",{"title":1838,"path":1839,"stem":1840},"Datasets API and CLI","\u002Fdatasets\u002Fapi-cli","04.datasets\u002F7.api-cli",{"title":1842,"path":1843,"stem":1844,"children":1845},"Agent","\u002Fagent","05.agent",[1846,1849,1853],{"title":1847,"path":1843,"stem":1848},"BH Agent","05.agent\u002Findex",{"title":1850,"path":1851,"stem":1852},"BH Agent Overview","\u002Fagent\u002Foverview","05.agent\u002F1.overview",{"title":1854,"path":1855,"stem":1856},"MCP servers","\u002Fagent\u002Fmcp-servers","05.agent\u002F2.mcp-servers",{"title":1858,"path":1859,"stem":1860,"children":1861},"Bhlast","\u002Fbhlast","06.bhlast",[1862,1865],{"title":1863,"path":1859,"stem":1864},"Bhlast Servers","06.bhlast\u002Findex",{"title":1866,"path":1867,"stem":1868},"Bhlast servers overview","\u002Fbhlast\u002Foverview","06.bhlast\u002F1.overview",{"title":1870,"path":1871,"stem":1872,"children":1873},"Notifications","\u002Fnotifications","07.notifications",[1874,1876],{"title":1870,"path":1871,"stem":1875},"07.notifications\u002Findex",{"title":1877,"path":1878,"stem":1879},"Notifications Overview","\u002Fnotifications\u002Foverview","07.notifications\u002F1.overview",{"title":1881,"path":1882,"stem":1883,"children":1884},"Blob Storage","\u002Fblob-storage","08.blob-storage",[1885,1887],{"title":1881,"path":1882,"stem":1886},"08.blob-storage\u002Findex",{"title":1888,"path":1889,"stem":1890},"Blob Storage Overview","\u002Fblob-storage\u002Foverview","08.blob-storage\u002F1.overview",{"title":1892,"path":1893,"stem":1894,"children":1895},"Payloads","\u002Fpayloads","09.payloads",[1896,1898],{"title":1892,"path":1893,"stem":1897},"09.payloads\u002Findex",{"title":1899,"path":1900,"stem":1901},"Payloads overview","\u002Fpayloads\u002Foverview","09.payloads\u002F1.overview",{"title":1903,"path":1904,"stem":1905,"children":1906},"Cve Watcher","\u002Fcve-watcher","10.cve-watcher",[1907,1910,1914,1918,1922],{"title":1908,"path":1904,"stem":1909},"CVE Watcher","10.cve-watcher\u002Findex",{"title":1911,"path":1912,"stem":1913},"CVE Watcher Overview","\u002Fcve-watcher\u002Foverview","10.cve-watcher\u002F1.overview",{"title":1915,"path":1916,"stem":1917},"CVE Watcher Search and Filters","\u002Fcve-watcher\u002Fsearch","10.cve-watcher\u002F2.search",{"title":1919,"path":1920,"stem":1921},"CVE Watcher Push Notifications","\u002Fcve-watcher\u002Fnotifications","10.cve-watcher\u002F3.notifications",{"title":1923,"path":1924,"stem":1925},"CVE Watcher API and Scopes","\u002Fcve-watcher\u002Fapi","10.cve-watcher\u002F4.api",{"title":1927,"path":1928,"stem":1929,"children":1930},"Developer","\u002Fdeveloper","11.developer",[1931,1933,1937,1941],{"title":1927,"path":1928,"stem":1932},"11.developer\u002Findex",{"title":1934,"path":1935,"stem":1936},"Developer Overview","\u002Fdeveloper\u002Foverview","11.developer\u002F1.overview",{"title":1938,"path":1939,"stem":1940},"Personal Access Token Scopes","\u002Fdeveloper\u002Fscopes","11.developer\u002F2.scopes",{"title":1942,"path":1943,"stem":1944},"Personal Access Tokens","\u002Fdeveloper\u002Fpersonal-access-tokens","11.developer\u002F3.personal-access-tokens",{"title":1946,"path":1947,"stem":1948,"children":1949},"Bh","\u002Fbh","12.bh",[1950,1953,1957,1961],{"title":1951,"path":1947,"stem":1952},"BH CLI","12.bh\u002Findex",{"title":1954,"path":1955,"stem":1956},"BH CLI Overview","\u002Fbh\u002Foverview","12.bh\u002F1.overview",{"title":1958,"path":1959,"stem":1960},"BH CLI Commands","\u002Fbh\u002Fcommands","12.bh\u002F2.commands",{"title":1962,"path":1963,"stem":1964},"BH CLI Examples","\u002Fbh\u002Fexamples","12.bh\u002F3.examples",{"title":1966,"path":1967,"stem":1968,"children":1969},"Billing","\u002Fbilling","13.billing",[1970,1972],{"title":1966,"path":1967,"stem":1971},"13.billing\u002Findex",{"title":1973,"path":1974,"stem":1975},"Billing Overview","\u002Fbilling\u002Foverview","13.billing\u002F1.overview",{"title":1977,"path":1978,"stem":1979,"children":1980},"Tools","\u002Ftools","14.tools",[1981,1983],{"title":1977,"path":1978,"stem":1982},"14.tools\u002Findex",{"title":1984,"path":1985,"stem":1986},"Cookie Lab","\u002Ftools\u002Fcookie-lab","14.tools\u002F1.cookie-lab",{"title":1988,"path":1989,"stem":1990,"children":1991},"Site Policies","\u002Fsite-policies","99.site-policies",[1992,1994,2007,2011,2015,2019,2023,2027,2031],{"title":1988,"path":1989,"stem":1993},"99.site-policies\u002Findex",{"title":1995,"path":1996,"stem":1997,"children":1998},"Privacy Policy","\u002Fsite-policies\u002Fprivacy-policy","99.site-policies\u002F1.privacy-policy",[1999,2003],{"title":2000,"path":2001,"stem":2002},"Company Processors","\u002Fsite-policies\u002Fprivacy-policy\u002Fcompany-processors","99.site-policies\u002Fprivacy-policy\u002F1.company-processors",{"title":2004,"path":2005,"stem":2006},"Data Export Instructions","\u002Fsite-policies\u002Fprivacy-policy\u002Fdata-export-instructions","99.site-policies\u002Fprivacy-policy\u002F2.data-export-instructions",{"title":2008,"path":2009,"stem":2010},"Terms of Service","\u002Fsite-policies\u002Fterms-of-service","99.site-policies\u002F2.terms-of-service",{"title":2012,"path":2013,"stem":2014},"California Resident Notice at Collection","\u002Fsite-policies\u002Fccpa","99.site-policies\u002F3.ccpa",{"title":2016,"path":2017,"stem":2018},"Cancellation Policy","\u002Fsite-policies\u002Fcancellation-policy","99.site-policies\u002F4.cancellation-policy",{"title":2020,"path":2021,"stem":2022},"Refund Policy","\u002Fsite-policies\u002Frefund-policy","99.site-policies\u002F5.refund-policy",{"title":2024,"path":2025,"stem":2026},"Taxes on Services","\u002Fsite-policies\u002Ftaxes-on-services","99.site-policies\u002F6.taxes-on-services",{"title":2028,"path":2029,"stem":2030},"Disclaimer","\u002Fsite-policies\u002Fdisclaimer","99.site-policies\u002F7.disclaimer",{"title":2032,"path":2033,"stem":2034,"children":2035},"Security","\u002Fsite-policies\u002Fsecurity","99.site-policies\u002Fsecurity\u002Findex",[2036,2037,2041],{"title":2032,"path":2033,"stem":2034},{"title":2038,"path":2039,"stem":2040},"Security Overview","\u002Fsite-policies\u002Fsecurity\u002Fsecurity-overview","99.site-policies\u002Fsecurity\u002F1.security-overview",{"title":2042,"path":2043,"stem":2044},"Security Response","\u002Fsite-policies\u002Fsecurity\u002Fsecurity-response","99.site-policies\u002Fsecurity\u002F2.security-response",1794410312375]