[{"data":1,"prerenderedAt":2912},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fextensions":3,"docs-nav":2803},{"id":4,"title":5,"body":6,"description":2795,"extension":2796,"meta":2797,"navigation":853,"order":2798,"path":2799,"seo":2800,"stem":2801,"__hash__":2802},"docs\u002Fdocs\u002F11.extensions.md","Extensions",{"type":7,"value":8,"toc":2776},"minimark",[9,27,41,48,71,84,102,126,131,141,333,341,360,364,372,382,392,408,425,429,456,461,475,481,485,533,546,591,597,604,648,652,671,699,704,722,726,804,808,819,965,991,1247,1270,1274,1337,1356,1366,1370,1387,1395,1400,1858,1886,1890,1895,1927,1959,1962,1991,1996,2057,2063,2067,2078,2142,2149,2337,2357,2392,2395,2486,2499,2503,2548,2638,2656,2660,2663,2740,2744,2761,2764,2772],[10,11,12,13,17,18,22,23,26],"p",{},"An ",[14,15,16],"strong",{},"extension"," is a package that adds tools to jawb. Its tools appear in\n",[19,20,21],"code",{},"jawb tools"," beside the WebMCP tools a page declares, marked as coming from\nthe extension, and you run them with ",[19,24,25],{},"jawb tool call",". Every step an\nextension takes is an ordinary jawb command, so the same per-action policy,\nconfirmations and trace apply: a cheaper route is never a weaker one.",[28,29,30],"blockquote",{},[10,31,32,33,36,37,40],{},"Not in a release yet: extensions need ",[19,34,35],{},"jawbd"," at API level 18, and jawb's\nbuilt-in extensions need level 20, with the ",[19,38,39],{},"jawb"," CLI after 0.1.1. jawb\n0.1.1 and earlier have neither.",[10,42,43,44,47],{},"Version 0 runs one shape, ",[14,45,46],{},"workflow",": a flat list of jawb steps that\nproduces something, such as a report. There are two workflow extensions:",[49,50,51,62],"ul",{},[52,53,54,61],"li",{},[55,56,58],"a",{"href":57},"#appjawbuat-acceptance-tests-with-a-report",[19,59,60],{},"app.jawb.uat"," runs\nacceptance criteria against a site you develop and writes a report with\na verdict per criterion.",[52,63,64,70],{},[55,65,67],{"href":66},"#appjawbscreens-screenshots-across-viewports-and-colour-schemes",[19,68,69],{},"app.jawb.screens","\nscreenshots pages of a site you develop at each viewport and colour\nscheme in one call.",[10,72,73,74,79,80,83],{},"Both are ",[14,75,76,77],{},"built into ",[19,78,35],{},": their files are part of the jawbd binary\nyou installed, so ",[19,81,82],{},"jawb extension install app.jawb.uat"," needs no download,\nand you still approve what it may do.",[10,85,86,89,90,93,94,97,98,101],{},[14,87,88],{},"Extension ids"," are reverse-DNS names, like mobile app bundle ids: a\ndomain the publisher controls, reversed, then the name (",[19,91,92],{},"com.example.tool","),\nor ",[19,95,96],{},"io.github.\u003Cuser>.\u003Cname>"," without a domain. ",[19,99,100],{},"app.jawb.*"," is jawb's own\nand is only used by the built-in extensions.",[10,103,104,107,108,111,112,115,116,118,119,111,122,125],{},[14,105,106],{},"Tool names"," belong to their extension: the full name is the extension id\nplus the tool's own name (",[19,109,110],{},"app.jawb.uat.run",", ",[19,113,114],{},"app.jawb.screens.capture","),\nso two extensions never clash. ",[19,117,25],{}," also takes any shorter\nending of the full name (",[19,120,121],{},"uat.run",[19,123,124],{},"run",") while only one installed tool\nmatches it; when two do, it exits 2 and lists the full names.",[127,128,130],"h2",{"id":129},"commands","Commands",[10,132,133,136,137,140],{},[19,134,135],{},"jawb extension"," has the short alias ",[19,138,139],{},"jawb ext",".",[142,143,144,157],"table",{},[145,146,147],"thead",{},[148,149,150,154],"tr",{},[151,152,153],"th",{},"Command",[151,155,156],{},"What it does",[158,159,160,188,198,221,248,265,279,293,310,323],"tbody",{},[148,161,162,168],{},[163,164,165],"td",{},[19,166,167],{},"jawb extension list",[163,169,170,171,111,174,111,177,111,180,183,184,187],{},"Installed extensions: id, version, how far jawb vouches for it (",[19,172,173],{},"[built-in]",[19,175,176],{},"[listed]",[19,178,179],{},"[unlisted]",[19,181,182],{},"[unlisted, was listed]"," or ",[19,185,186],{},"[dev]","), enabled or disabled (and why), how consent was given, and their tools. Also the built-in extensions not installed yet, and the catalogue index's serial and expiry.",[148,189,190,195],{},[163,191,192],{},[19,193,194],{},"jawb extension info \u003Cid>",[163,196,197],{},"One extension: its manifest, what it may do (origins, sessions, secrets, files) and its tools.",[148,199,200,205],{},[163,201,202],{},[19,203,204],{},"jawb extension install \u003Cid>[@\u003Cversion>]",[163,206,207,208,210,211,213,214,217,218,220],{},"A built-in extension (",[19,209,100],{},") installs from the copy inside ",[19,212,35],{},", with no download. Any other id: downloads the signed catalogue index and the package from ",[19,215,216],{},"get.jawb.app",", hands them to ",[19,219,35],{},". Either way it asks for your consent.",[148,222,223,228],{},[163,224,225],{},[19,226,227],{},"jawb extension install --file \u003Cpkg>",[163,229,230,231,234,235,239,240,243,244,140],{},"A third-party extension from a ",[19,232,233],{},".tar.gz"," on disk. It installs as ",[236,237,238],"em",{},"listed"," when jawb's signed index lists these exact bytes, else as ",[236,241,242],{},"unlisted",", and the consent says which. See ",[55,245,247],{"href":246},"#third-party-extensions","Third-party extensions",[148,249,250,255],{},[163,251,252],{},[19,253,254],{},"jawb extension install https:\u002F\u002F…\u002Fx.tar.gz#sha256=\u003Chex>",[163,256,257,258,261,262,264],{},"The same from an https URL. The ",[19,259,260],{},"#sha256="," pin is optional; with it, a download that does not match is refused before ",[19,263,35],{}," sees it.",[148,266,267,272],{},[163,268,269],{},[19,270,271],{},"jawb extension load --dev \u003Cdir>",[163,273,274,275,278],{},"Loads an unpacked extension directory for development: unsigned, labelled ",[19,276,277],{},"dev"," everywhere, never updated from the catalogue, and still needs your consent.",[148,280,281,286],{},[163,282,283],{},[19,284,285],{},"jawb extension remove \u003Cid>",[163,287,288,289,292],{},"Removes it and its files. Asks first; ",[19,290,291],{},"--yes"," skips the question.",[148,294,295,300],{},[163,296,297],{},[19,298,299],{},"jawb extension refresh",[163,301,302,303,305,306,309],{},"Sends ",[19,304,35],{}," the newest signed index, so revocations reach it. Also ",[19,307,308],{},"jawb extension index",". The daily background update check does this too when a daemon is running.",[148,311,312,316],{},[163,313,314],{},[19,315,21],{},[163,317,318,319,322],{},"Lists extension tools, plus the page's tools when there is a current tab (or ",[19,320,321],{},"--tab",").",[148,324,325,330],{},[163,326,327],{},[19,328,329],{},"jawb tool call \u003Cname> --input \u003Cjson|@file>",[163,331,332],{},"Runs an extension tool.",[10,334,335,337,338,340],{},[19,336,35],{}," never downloads anything for extensions. The CLI fetches the files\nand ",[19,339,35],{}," verifies them against the public keys compiled into it, so the\ntrust decision is made in one place. A changed byte fails verification.",[10,342,343,344,347,348,352,353,355,356,359],{},"With ",[19,345,346],{},"--json"," every command prints the usual\n",[55,349,351],{"href":350},"\u002Fdocs\u002Fcli\u002Fjson-and-exit-codes","JSON envelope",". An older ",[19,354,35],{}," is refused\nwith ",[19,357,358],{},"E_VERSION_MISMATCH"," (exit 3).",[127,361,363],{"id":362},"installing","Installing",[10,365,366,367,371],{},"Installing or loading an extension is held for you, the same way a\npurchase is (",[55,368,370],{"href":369},"\u002Fdocs\u002Fcli\u002Fpolicy","Policy and confirmation","). Nothing is\nwritten until you approve.",[10,373,374,375,377,378,381],{},"On an interactive terminal, ",[19,376,39],{}," shows what the extension may do and\nasks you to type ",[19,379,380],{},"install",":",[383,384,390],"pre",{"className":385,"code":387,"language":388,"meta":389},[386],"language-text","$ jawb extension install app.jawb.uat\njawb: installing an extension needs your consent (pc_8rwvaktb6c7p):\n  extension: app.jawb.uat 0.1.0 from jawb (built into jawbd)\n  purpose:   Run acceptance criteria against a site you develop and write a verdict report with evidence\n  shape:     workflow\n  origins:   http:\u002F\u002Flocalhost:*, http:\u002F\u002F127.0.0.1:*\n  sessions:  incognito, profile:uat\n  secrets:   uat.username, uat.password\n  files:     write:jawb-uat\n  network:\n  - reads from http:\u002F\u002Flocalhost:*, http:\u002F\u002F127.0.0.1:* with the sessions incognito, profile:uat\n  - sends nothing to other domains\n  - writes files under jawb-uat (relative to the working directory)\n  - fills the vault secrets uat.username, uat.password\n  An extension never approves anything; purchase-like actions stay held for you.\nType `install` to approve it, or `deny` to decline it:\n","text","",[19,391,387],{"__ignoreMap":389},[10,393,394,395,397,398,401,402,404,405,407],{},"Where the operating system can verify you (Windows Hello, Touch ID), it\nasks too. Anywhere else (",[19,396,346],{},", a script, an agent) the command exits 5\nwith the pending id, and a person approves it later with\n",[19,399,400],{},"jawb confirm \u003Cpc_id>",", which also asks for ",[19,403,380],{},". ",[19,406,291],{}," never\napproves an install. An update that asks for more (more origins, sessions,\nsecrets, files or a higher effect ceiling) asks again and lists what\nwidens.",[10,409,410,413,414,416,417,420,421,424],{},[14,411,412],{},"Consent is \"asserted\" unless verified."," ",[19,415,167],{}," shows\n",[19,418,419],{},"consent verified"," only when the operating system verified the person who\napproved. Otherwise it says ",[19,422,423],{},"asserted",": a program running as you could\nhave approved it.",[426,427,247],"h3",{"id":428},"third-party-extensions",[10,430,431,433,434,437,438,440,441,443,444,447,448,451,452,455],{},[19,432,227],{}," and ",[19,435,436],{},"jawb extension install \u003Chttps-url>"," install an extension someone else publishes. They need ",[19,439,35],{},"\nAPI level 28 and a current signed index from jawb, so ",[19,442,35],{}," can switch off\na revoked package. ",[14,445,446],{},"jawb does not publish that index yet",", so until it\ndoes these installs are refused (",[19,449,450],{},"not_in_index","); ",[19,453,454],{},"load --dev"," loads one you\nare developing.",[10,457,458,460],{},[19,459,35],{}," labels each install by what jawb knows about the bytes:",[49,462,463,469],{},[52,464,465,468],{},[14,466,467],{},"listed:"," jawb's index lists these exact bytes. They passed jawb Hub's\nautomated checks, which is not a review. The publisher shown is the\nlisting's owner.",[52,470,471,474],{},[14,472,473],{},"unlisted:"," jawb has not checked it. The consent shows where it came\nfrom, and the publisher named in its manifest is shown as a claim, not a\nfact.",[10,476,477,478,480],{},"An unlisted package cannot reuse a listed id with other bytes, and no\nthird-party package may use jawb's name as its publisher or an ",[19,479,100],{},"\nid. Every install pins its sha256. Any new version of a listed or unlisted\nextension asks you again, even one that asks for less, and so does the same\npackage from another source. Only workflows install this way for now.",[127,482,484],{"id":483},"running-a-tool","Running a tool",[383,486,490],{"className":487,"code":488,"language":489,"meta":389,"style":389},"language-bash shiki shiki-themes github-light github-dark","jawb tool call uat.run --input '{\"scenario\": \"checks\u002Fhome.toml\"}'\njawb tool call uat.run --input @input.json\n","bash",[19,491,492,517],{"__ignoreMap":389},[493,494,497,500,504,507,510,514],"span",{"class":495,"line":496},"line",1,[493,498,39],{"class":499},"sScJk",[493,501,503],{"class":502},"sZZnC"," tool",[493,505,506],{"class":502}," call",[493,508,509],{"class":502}," uat.run",[493,511,513],{"class":512},"sj4cs"," --input",[493,515,516],{"class":502}," '{\"scenario\": \"checks\u002Fhome.toml\"}'\n",[493,518,520,522,524,526,528,530],{"class":495,"line":519},2,[493,521,39],{"class":499},[493,523,503],{"class":502},[493,525,506],{"class":502},[493,527,509],{"class":502},[493,529,513],{"class":512},[493,531,532],{"class":502}," @input.json\n",[10,534,535,537,538,540,541,543,544,381],{},[19,536,25],{}," looks the tool up, registers a ",[14,539,124],{}," with ",[19,542,35],{},"\n(which checks the input against the tool's schema), runs the steps, and\nends the run. Every step carries the run's id, so ",[19,545,35],{},[49,547,548,555,568,574,580],{},[52,549,550,551,554],{},"refuses to open or act on an origin outside the extension's origins\n(",[19,552,553],{},"outside_matches","), including after a redirect;",[52,556,557,558,111,561,111,564,567],{},"refuses a session, a vault secret or an effect it was not granted\n(",[19,559,560],{},"session_not_granted",[19,562,563],{},"secret_not_granted",[19,565,566],{},"exceeds_max_effect",");",[52,569,570,571,567],{},"stops the run at its step and time limits (",[19,572,573],{},"run_limit",[52,575,576,577,567],{},"lets a run call only page commands: never configuration, profiles,\nsecrets, cookies, storage or other extensions, and never an approval\n(",[19,578,579],{},"outside_run_scope",[52,581,582,583,586,587,590],{},"records the extension and the run on every trace step, labelled\n",[19,584,585],{},"attribution: \"client-claim\""," (",[19,588,589],{},"jawb trace"," shows it).",[10,592,593,594,596],{},"The steps run in the CLI, as an ordinary client of ",[19,595,35],{},". These checks\nbound what a step that names a run may do. They are not a sandbox.",[10,598,599],{},[14,600,601,602,381],{},"Exit codes of ",[19,603,25],{},[142,605,606,616],{},[145,607,608],{},[148,609,610,613],{},[151,611,612],{},"Exit",[151,614,615],{},"Meaning",[158,617,618,626,637],{},[148,619,620,623],{},[163,621,622],{},"0",[163,624,625],{},"The run finished. Its verdicts are in the output and the report, whatever they are.",[148,627,628,631],{},[163,629,630],{},"2",[163,632,633,634,636],{},"Configuration error: bad input, an invalid scenario, an unknown or ungranted secret, an origin outside the extension's origins, an unusable output directory, an unknown tool, or a ",[19,635,35],{}," too old for extensions.",[148,638,639,642],{},[163,640,641],{},"3",[163,643,644,645,647],{},"Harness drift: ",[19,646,35],{}," is not running or was lost, the browser bridge is off or missing, or the site under test does not answer. No verdicts are published.",[127,649,651],{"id":650},"appjawbuat-acceptance-tests-with-a-report","app.jawb.uat: acceptance tests with a report",[10,653,654,656,657,183,660,663,664,433,667,670],{},[19,655,60],{}," runs the acceptance criteria of a scenario file against a site\non ",[19,658,659],{},"localhost",[19,661,662],{},"127.0.0.1",", and writes ",[19,665,666],{},"report.md",[19,668,669],{},"report.json","\nwith one verdict per criterion, screenshots and trace ids.",[10,672,673,674,433,677,680,681,684,685,433,688,691,692,695,696,140],{},"Its grants: the origins ",[19,675,676],{},"http:\u002F\u002Flocalhost:*",[19,678,679],{},"http:\u002F\u002F127.0.0.1:*","; an\nincognito tab per criterion, or the ",[19,682,683],{},"uat"," profile; the vault secrets\n",[19,686,687],{},"uat.username",[19,689,690],{},"uat.password","; files under ",[19,693,694],{},".\u002Fjawb-uat"," in the\nworking directory; at most 500 steps and 900 seconds per run; and the\neffect ceiling ",[19,697,698],{},"submit",[10,700,701,702,381],{},"It is built into ",[19,703,35],{},[383,705,707],{"className":487,"code":706,"language":489,"meta":389,"style":389},"jawb extension install app.jawb.uat\n",[19,708,709],{"__ignoreMap":389},[493,710,711,713,716,719],{"class":495,"line":496},[493,712,39],{"class":499},[493,714,715],{"class":502}," extension",[493,717,718],{"class":502}," install",[493,720,721],{"class":502}," app.jawb.uat\n",[426,723,725],{"id":724},"tools","Tools",[49,727,728,738],{},[52,729,730,733,734,737],{},[19,731,732],{},"app.jawb.uat.validate {scenario}"," checks a scenario and opens no page. It\nreturns ",[19,735,736],{},"{ok, errors, unsupported_steps}"," and exits 0 when the scenario\nis valid, 2 when it is not.",[52,739,740,743,744],{},[19,741,742],{},"app.jawb.uat.run {scenario, profile?, incognito?, out_dir?, stop_on_first_fail?, step_timeout_ms?}","\nruns it.\n",[49,745,746,752,768,788,794],{},[52,747,748,751],{},[19,749,750],{},"scenario",": a path to the scenario file (relative to the working\ndirectory), or the TOML inline.",[52,753,754,757,758,761,762,764,765,322],{},[19,755,756],{},"profile",": ",[19,759,760],{},"\"uat\""," runs every criterion in the ",[19,763,683],{}," profile instead\nof incognito (needed for ",[19,766,767],{},"fill_secret",[52,769,770,773,774,776,777,780,781,784,785,787],{},[19,771,772],{},"out_dir",": where the report goes, inside ",[19,775,694],{},". The default is\n",[19,778,779],{},"jawb-uat\u002F\u003Cscenario id>",". A path with ",[19,782,783],{},"..",", or one that leads out of\n",[19,786,694],{}," through a link, is a configuration error.",[52,789,790,793],{},[19,791,792],{},"stop_on_first_fail",": after a FAIL, the remaining criteria are\nreported UNCERTAIN, \"not run\".",[52,795,796,799,800,803],{},[19,797,798],{},"step_timeout_ms",": how long each ",[19,801,802],{},"expect_*"," step waits (default\n10000).",[426,805,807],{"id":806},"scenario-format","Scenario format",[10,809,810,811,814,815,818],{},"A scenario is a TOML file: a ",[19,812,813],{},"[scenario]"," table and one ",[19,816,817],{},"[[criteria]]","\nentry per acceptance criterion, each a flat list of steps. There are no\nloops, conditionals or references to an earlier step's output. An unknown\nkey or step is an error, never ignored.",[383,820,824],{"className":821,"code":822,"language":823,"meta":389,"style":389},"language-toml shiki shiki-themes github-light github-dark","[scenario]\nid = \"issue-83-hero\"\nbase_url = \"http:\u002F\u002Flocalhost:3000\"\nissue = \"4hum-ai\u002Fjawb#83\"            # optional, copied into the report\n\n[[criteria]]\nid = \"AC1\"\ntext = \"The home page shows the product name in the hero\"\nsteps = [\n  { open = \"\u002F\" },\n  { expect_text = \"jawb\" },\n  { screens = { viewports = [\"mobile\", \"desktop\"], schemes = [\"light\", \"dark\"] } },\n]\n\n[[criteria]]\nid = \"AC2\"\ntext = \"Signing in with a valid account reaches the dashboard\"\nsteps = [\n  { open = \"\u002Flogin\" },\n  { fill = { target = { role = \"textbox\", text = \"Email\" }, value = \"uat@example.test\" } },\n  { fill_secret = { target = { css = \"input[name=code]\" }, ref = \"uat.username\" } },\n  { click = { text = \"Sign in\" } },\n  { expect_url = \"**\u002Fdashboard\", timeout_ms = 5000 },\n]\n","toml",[19,825,826,831,836,842,848,855,861,867,873,879,885,891,897,903,908,913,919,925,930,936,942,948,954,960],{"__ignoreMap":389},[493,827,828],{"class":495,"line":496},[493,829,830],{},"[scenario]\n",[493,832,833],{"class":495,"line":519},[493,834,835],{},"id = \"issue-83-hero\"\n",[493,837,839],{"class":495,"line":838},3,[493,840,841],{},"base_url = \"http:\u002F\u002Flocalhost:3000\"\n",[493,843,845],{"class":495,"line":844},4,[493,846,847],{},"issue = \"4hum-ai\u002Fjawb#83\"            # optional, copied into the report\n",[493,849,851],{"class":495,"line":850},5,[493,852,854],{"emptyLinePlaceholder":853},true,"\n",[493,856,858],{"class":495,"line":857},6,[493,859,860],{},"[[criteria]]\n",[493,862,864],{"class":495,"line":863},7,[493,865,866],{},"id = \"AC1\"\n",[493,868,870],{"class":495,"line":869},8,[493,871,872],{},"text = \"The home page shows the product name in the hero\"\n",[493,874,876],{"class":495,"line":875},9,[493,877,878],{},"steps = [\n",[493,880,882],{"class":495,"line":881},10,[493,883,884],{},"  { open = \"\u002F\" },\n",[493,886,888],{"class":495,"line":887},11,[493,889,890],{},"  { expect_text = \"jawb\" },\n",[493,892,894],{"class":495,"line":893},12,[493,895,896],{},"  { screens = { viewports = [\"mobile\", \"desktop\"], schemes = [\"light\", \"dark\"] } },\n",[493,898,900],{"class":495,"line":899},13,[493,901,902],{},"]\n",[493,904,906],{"class":495,"line":905},14,[493,907,854],{"emptyLinePlaceholder":853},[493,909,911],{"class":495,"line":910},15,[493,912,860],{},[493,914,916],{"class":495,"line":915},16,[493,917,918],{},"id = \"AC2\"\n",[493,920,922],{"class":495,"line":921},17,[493,923,924],{},"text = \"Signing in with a valid account reaches the dashboard\"\n",[493,926,928],{"class":495,"line":927},18,[493,929,878],{},[493,931,933],{"class":495,"line":932},19,[493,934,935],{},"  { open = \"\u002Flogin\" },\n",[493,937,939],{"class":495,"line":938},20,[493,940,941],{},"  { fill = { target = { role = \"textbox\", text = \"Email\" }, value = \"uat@example.test\" } },\n",[493,943,945],{"class":495,"line":944},21,[493,946,947],{},"  { fill_secret = { target = { css = \"input[name=code]\" }, ref = \"uat.username\" } },\n",[493,949,951],{"class":495,"line":950},22,[493,952,953],{},"  { click = { text = \"Sign in\" } },\n",[493,955,957],{"class":495,"line":956},23,[493,958,959],{},"  { expect_url = \"**\u002Fdashboard\", timeout_ms = 5000 },\n",[493,961,963],{"class":495,"line":962},24,[493,964,902],{},[10,966,967,968,971,972,975,976,978,979,982,983,986,987,990],{},"Each criterion runs in its own new tab, which is closed at the end\nwhatever happens, so its first step must be ",[19,969,970],{},"open",". A target is visible\ntext (",[19,973,974],{},"\"Sign in\"",") or a table with ",[19,977,388],{}," and\u002For ",[19,980,981],{},"role",", or ",[19,984,985],{},"css",", plus\n",[19,988,989],{},"nth"," when several elements match. Element ids are not accepted: they\nbelong to one observation.",[142,992,993,1003],{},[145,994,995],{},[148,996,997,1000],{},[151,998,999],{},"Step",[151,1001,1002],{},"What it runs",[158,1004,1005,1024,1044,1056,1068,1081,1093,1109,1124,1142,1168,1181,1218,1232],{},[148,1006,1007,1012],{},[163,1008,1009],{},[19,1010,1011],{},"open = \"\u003Cpath or URL>\"",[163,1013,1014,1016,1017,1020,1021,140],{},[19,1015,970],{}," (the first step opens the tab), then ",[19,1018,1019],{},"open --tab"," for later ones. Paths join ",[19,1022,1023],{},"base_url",[148,1025,1026,1041],{},[163,1027,1028,111,1031,111,1034,111,1037,1040],{},[19,1029,1030],{},"click",[19,1032,1033],{},"hover",[19,1035,1036],{},"check",[19,1038,1039],{},"uncheck"," = target",[163,1042,1043],{},"The Act command of the same name.",[148,1045,1046,1052],{},[163,1047,1048,1051],{},[19,1049,1050],{},"submit = true"," or target",[163,1053,1054,140],{},[19,1055,698],{},[148,1057,1058,1063],{},[163,1059,1060],{},[19,1061,1062],{},"fill = { target, value }",[163,1064,1065,140],{},[19,1066,1067],{},"fill",[148,1069,1070,1075],{},[163,1071,1072],{},[19,1073,1074],{},"fill_secret = { target, ref }",[163,1076,1077,1080],{},[19,1078,1079],{},"fill --secret-from vault:\u003Cref>"," in the run's profile. The value never reaches the CLI, the report or the trace.",[148,1082,1083,1088],{},[163,1084,1085],{},[19,1086,1087],{},"type = { target, text, delay_ms? }",[163,1089,1090,140],{},[19,1091,1092],{},"type",[148,1094,1095,1100],{},[163,1096,1097],{},[19,1098,1099],{},"select = { target, value or values, by? }",[163,1101,1102,586,1105,1108],{},[19,1103,1104],{},"select",[19,1106,1107],{},"by = \"label\""," to match labels).",[148,1110,1111,1119],{},[163,1112,1113,183,1116],{},[19,1114,1115],{},"press = \"Enter\"",[19,1117,1118],{},"{ key, target? }",[163,1120,1121,140],{},[19,1122,1123],{},"press",[148,1125,1126,1137],{},[163,1127,1128,111,1131,183,1134],{},[19,1129,1130],{},"scroll = \"top\"",[19,1132,1133],{},"\"bottom\"",[19,1135,1136],{},"{ by = [x, y] }",[163,1138,1139,140],{},[19,1140,1141],{},"scroll",[148,1143,1144,1155],{},[163,1145,1146,111,1149,111,1152],{},[19,1147,1148],{},"expect_text",[19,1150,1151],{},"expect_element",[19,1153,1154],{},"expect_url",[163,1156,1157,1160,1161,1160,1164,1167],{},[19,1158,1159],{},"wait --for text:"," \u002F ",[19,1162,1163],{},"element:",[19,1165,1166],{},"url:"," with the step timeout.",[148,1169,1170,1175],{},[163,1171,1172],{},[19,1173,1174],{},"expect_no_text = \"...\"",[163,1176,1177,1180],{},[19,1178,1179],{},"read --format text --full",", then a check that the text is absent.",[148,1182,1183,1188],{},[163,1184,1185],{},[19,1186,1187],{},"screens = { viewports, schemes }",[163,1189,1190,1191,111,1194,183,1197,1200,1201,111,1204,1207,1208,111,1211,111,1214,1217],{},"For each viewport (",[19,1192,1193],{},"mobile",[19,1195,1196],{},"desktop",[19,1198,1199],{},"WxH",") and scheme (",[19,1202,1203],{},"light",[19,1205,1206],{},"dark","): ",[19,1209,1210],{},"viewport",[19,1212,1213],{},"emulate",[19,1215,1216],{},"screenshot",". At most 8 combinations.",[148,1219,1220,1228],{},[163,1221,1222,183,1225],{},[19,1223,1224],{},"screenshot = true",[19,1226,1227],{},"{ full = true }",[163,1229,1230,140],{},[19,1231,1216],{},[148,1233,1234,1241],{},[163,1235,1236,183,1239],{},[19,1237,1238],{},"capture = true",[19,1240,1227],{},[163,1242,1243,1246],{},[19,1244,1245],{},"read --format md","; the first 2000 characters go into the report, marked as untrusted page content.",[10,1248,1249,1250,404,1253,111,1256,433,1259,1262,1263,1266,1267,140],{},"Any step may add ",[19,1251,1252],{},"timeout_ms",[19,1254,1255],{},"upload",[19,1257,1258],{},"download",[19,1260,1261],{},"media"," are known\nbut not run in version 0; ",[19,1264,1265],{},"uat.validate"," lists them under\n",[19,1268,1269],{},"unsupported_steps",[426,1271,1273],{"id":1272},"verdicts","Verdicts",[142,1275,1276,1286],{},[145,1277,1278],{},[148,1279,1280,1283],{},[151,1281,1282],{},"Verdict",[151,1284,1285],{},"When",[158,1287,1288,1296,1310,1321],{},[148,1289,1290,1293],{},[163,1291,1292],{},"PASS",[163,1294,1295],{},"Every step of the criterion succeeded.",[148,1297,1298,1301],{},[163,1299,1300],{},"FAIL",[163,1302,12,1303,1305,1306,1309],{},[19,1304,802],{}," step timed out, or ",[19,1307,1308],{},"expect_no_text"," found its text.",[148,1311,1312,1315],{},[163,1313,1314],{},"UNCERTAIN",[163,1316,1317,1318,1320],{},"A step could not run: no element matched, several matched, a stale or not actionable element after one re-observe, a timeout outside an ",[19,1319,802],{}," step, or any other error.",[148,1322,1323,1326],{},[163,1324,1325],{},"BLOCKED",[163,1327,1328,1329,1332,1333,1336],{},"jawb held an action for a person (",[19,1330,1331],{},"E_CONFIRMATION_REQUIRED",") or its policy refused it (",[19,1334,1335],{},"E_POLICY_DENIED","). The report names the pending id and its class.",[10,1338,1339,1340,1343,1344,1346,1347,1349,1350,1352,1353,1355],{},"BLOCKED means the action was not approved during this run. The runner\nnever approves anything, so BLOCKED is not evidence that a person saw it.\nA purchase-like click is always held, whatever the extension's ceiling.\nFilling a password field is a ",[19,1341,1342],{},"credential"," action, above ",[19,1345,121],{},"'s\nceiling (",[19,1348,698],{},"), so a ",[19,1351,767],{}," into a password field is reported\nBLOCKED with ",[19,1354,566],{},"; use it for other fields.",[10,1357,1358,1359,1361,1362,1365],{},"Harness drift is not a verdict: when ",[19,1360,35],{},", the browser bridge or the\nsite is missing, the run exits 3 and the report says ",[19,1363,1364],{},"harness_drift"," with\nthe step log only.",[426,1367,1369],{"id":1368},"the-report","The report",[10,1371,1372,1374,1375,433,1377,1379,1380,1383,1384,322],{},[19,1373,121],{}," writes ",[19,1376,666],{},[19,1378,669],{}," into the output directory,\nnext to its screenshots (",[19,1381,1382],{},"\u003Ccriterion>-\u003Cviewport>-\u003Cscheme>.png",",\n",[19,1385,1386],{},"\u003Ccriterion>-step\u003Cn>.png",[10,1388,1389,1391,1392,1394],{},[19,1390,666],{}," has a header (scenario, issue, base URL, ",[19,1393,35],{}," version and\nAPI level, session, start and end times, the run's outcome and id), a\ntable with one row per criterion (id, text, verdict, reason, evidence\nlinks, trace ids), and a step log per criterion.",[10,1396,1397,1399],{},[19,1398,669],{}," is the machine copy:",[383,1401,1405],{"className":1402,"code":1403,"language":1404,"meta":389,"style":389},"language-json shiki shiki-themes github-light github-dark","{\n  \"v\": 1,\n  \"tool\": \"uat.run\",\n  \"extension\": {\"id\": \"app.jawb.uat\", \"version\": \"0.1.0\", \"dev\": false},\n  \"run_id\": \"r_dgrp3wd6xa4v\",\n  \"attribution\": \"client-claim\",\n  \"scenario\": {\"id\": \"smoke\", \"issue\": null, \"base_url\": \"http:\u002F\u002F127.0.0.1:4392\", \"source\": \"smoke.toml\"},\n  \"session\": \"incognito\",\n  \"jawbd\": {\"version\": \"0.1.1\", \"api_level\": 18},\n  \"started_at\": \"2026-10-05T23:19:17Z\",\n  \"ended_at\": \"2026-10-05T23:19:20Z\",\n  \"duration_ms\": 3120,\n  \"run\": \"completed\",\n  \"exit_code\": 0,\n  \"summary\": {\"PASS\": 2, \"FAIL\": 1, \"UNCERTAIN\": 0, \"BLOCKED\": 0},\n  \"criteria\": [\n    {\"id\": \"AC2\", \"text\": \"missing\", \"verdict\": \"FAIL\",\n     \"reason\": \"expect_text: condition `text:Nope` not met within 800 ms\",\n     \"evidence\": [], \"trace_ids\": [\"tr_01m475tjcngethv5sv\", \"tr_01m475tjct11netq93\"],\n     \"steps\": [{\"n\": 2, \"command\": \"expect_text\", \"detail\": \"\\\"Nope\\\"\", \"outcome\": \"fail\",\n                \"duration_ms\": 813, \"trace_ids\": [\"tr_01m475tjct11netq93\"], \"evidence\": []}]}\n  ]\n}\n","json",[19,1406,1407,1413,1425,1437,1476,1488,1500,1546,1558,1584,1596,1608,1620,1632,1643,1686,1694,1727,1739,1764,1821,1848,1853],{"__ignoreMap":389},[493,1408,1409],{"class":495,"line":496},[493,1410,1412],{"class":1411},"sVt8B","{\n",[493,1414,1415,1418,1420,1423],{"class":495,"line":519},[493,1416,1417],{"class":512},"  \"v\"",[493,1419,757],{"class":1411},[493,1421,1422],{"class":512},"1",[493,1424,1383],{"class":1411},[493,1426,1427,1430,1432,1435],{"class":495,"line":838},[493,1428,1429],{"class":512},"  \"tool\"",[493,1431,757],{"class":1411},[493,1433,1434],{"class":502},"\"uat.run\"",[493,1436,1383],{"class":1411},[493,1438,1439,1442,1445,1448,1450,1453,1455,1458,1460,1463,1465,1468,1470,1473],{"class":495,"line":844},[493,1440,1441],{"class":512},"  \"extension\"",[493,1443,1444],{"class":1411},": {",[493,1446,1447],{"class":512},"\"id\"",[493,1449,757],{"class":1411},[493,1451,1452],{"class":502},"\"app.jawb.uat\"",[493,1454,111],{"class":1411},[493,1456,1457],{"class":512},"\"version\"",[493,1459,757],{"class":1411},[493,1461,1462],{"class":502},"\"0.1.0\"",[493,1464,111],{"class":1411},[493,1466,1467],{"class":512},"\"dev\"",[493,1469,757],{"class":1411},[493,1471,1472],{"class":512},"false",[493,1474,1475],{"class":1411},"},\n",[493,1477,1478,1481,1483,1486],{"class":495,"line":850},[493,1479,1480],{"class":512},"  \"run_id\"",[493,1482,757],{"class":1411},[493,1484,1485],{"class":502},"\"r_dgrp3wd6xa4v\"",[493,1487,1383],{"class":1411},[493,1489,1490,1493,1495,1498],{"class":495,"line":857},[493,1491,1492],{"class":512},"  \"attribution\"",[493,1494,757],{"class":1411},[493,1496,1497],{"class":502},"\"client-claim\"",[493,1499,1383],{"class":1411},[493,1501,1502,1505,1507,1509,1511,1514,1516,1519,1521,1524,1526,1529,1531,1534,1536,1539,1541,1544],{"class":495,"line":863},[493,1503,1504],{"class":512},"  \"scenario\"",[493,1506,1444],{"class":1411},[493,1508,1447],{"class":512},[493,1510,757],{"class":1411},[493,1512,1513],{"class":502},"\"smoke\"",[493,1515,111],{"class":1411},[493,1517,1518],{"class":512},"\"issue\"",[493,1520,757],{"class":1411},[493,1522,1523],{"class":512},"null",[493,1525,111],{"class":1411},[493,1527,1528],{"class":512},"\"base_url\"",[493,1530,757],{"class":1411},[493,1532,1533],{"class":502},"\"http:\u002F\u002F127.0.0.1:4392\"",[493,1535,111],{"class":1411},[493,1537,1538],{"class":512},"\"source\"",[493,1540,757],{"class":1411},[493,1542,1543],{"class":502},"\"smoke.toml\"",[493,1545,1475],{"class":1411},[493,1547,1548,1551,1553,1556],{"class":495,"line":869},[493,1549,1550],{"class":512},"  \"session\"",[493,1552,757],{"class":1411},[493,1554,1555],{"class":502},"\"incognito\"",[493,1557,1383],{"class":1411},[493,1559,1560,1563,1565,1567,1569,1572,1574,1577,1579,1582],{"class":495,"line":875},[493,1561,1562],{"class":512},"  \"jawbd\"",[493,1564,1444],{"class":1411},[493,1566,1457],{"class":512},[493,1568,757],{"class":1411},[493,1570,1571],{"class":502},"\"0.1.1\"",[493,1573,111],{"class":1411},[493,1575,1576],{"class":512},"\"api_level\"",[493,1578,757],{"class":1411},[493,1580,1581],{"class":512},"18",[493,1583,1475],{"class":1411},[493,1585,1586,1589,1591,1594],{"class":495,"line":881},[493,1587,1588],{"class":512},"  \"started_at\"",[493,1590,757],{"class":1411},[493,1592,1593],{"class":502},"\"2026-10-05T23:19:17Z\"",[493,1595,1383],{"class":1411},[493,1597,1598,1601,1603,1606],{"class":495,"line":887},[493,1599,1600],{"class":512},"  \"ended_at\"",[493,1602,757],{"class":1411},[493,1604,1605],{"class":502},"\"2026-10-05T23:19:20Z\"",[493,1607,1383],{"class":1411},[493,1609,1610,1613,1615,1618],{"class":495,"line":893},[493,1611,1612],{"class":512},"  \"duration_ms\"",[493,1614,757],{"class":1411},[493,1616,1617],{"class":512},"3120",[493,1619,1383],{"class":1411},[493,1621,1622,1625,1627,1630],{"class":495,"line":899},[493,1623,1624],{"class":512},"  \"run\"",[493,1626,757],{"class":1411},[493,1628,1629],{"class":502},"\"completed\"",[493,1631,1383],{"class":1411},[493,1633,1634,1637,1639,1641],{"class":495,"line":905},[493,1635,1636],{"class":512},"  \"exit_code\"",[493,1638,757],{"class":1411},[493,1640,622],{"class":512},[493,1642,1383],{"class":1411},[493,1644,1645,1648,1650,1653,1655,1657,1659,1662,1664,1666,1668,1671,1673,1675,1677,1680,1682,1684],{"class":495,"line":910},[493,1646,1647],{"class":512},"  \"summary\"",[493,1649,1444],{"class":1411},[493,1651,1652],{"class":512},"\"PASS\"",[493,1654,757],{"class":1411},[493,1656,630],{"class":512},[493,1658,111],{"class":1411},[493,1660,1661],{"class":512},"\"FAIL\"",[493,1663,757],{"class":1411},[493,1665,1422],{"class":512},[493,1667,111],{"class":1411},[493,1669,1670],{"class":512},"\"UNCERTAIN\"",[493,1672,757],{"class":1411},[493,1674,622],{"class":512},[493,1676,111],{"class":1411},[493,1678,1679],{"class":512},"\"BLOCKED\"",[493,1681,757],{"class":1411},[493,1683,622],{"class":512},[493,1685,1475],{"class":1411},[493,1687,1688,1691],{"class":495,"line":915},[493,1689,1690],{"class":512},"  \"criteria\"",[493,1692,1693],{"class":1411},": [\n",[493,1695,1696,1699,1701,1703,1706,1708,1711,1713,1716,1718,1721,1723,1725],{"class":495,"line":921},[493,1697,1698],{"class":1411},"    {",[493,1700,1447],{"class":512},[493,1702,757],{"class":1411},[493,1704,1705],{"class":502},"\"AC2\"",[493,1707,111],{"class":1411},[493,1709,1710],{"class":512},"\"text\"",[493,1712,757],{"class":1411},[493,1714,1715],{"class":502},"\"missing\"",[493,1717,111],{"class":1411},[493,1719,1720],{"class":512},"\"verdict\"",[493,1722,757],{"class":1411},[493,1724,1661],{"class":502},[493,1726,1383],{"class":1411},[493,1728,1729,1732,1734,1737],{"class":495,"line":927},[493,1730,1731],{"class":512},"     \"reason\"",[493,1733,757],{"class":1411},[493,1735,1736],{"class":502},"\"expect_text: condition `text:Nope` not met within 800 ms\"",[493,1738,1383],{"class":1411},[493,1740,1741,1744,1747,1750,1753,1756,1758,1761],{"class":495,"line":932},[493,1742,1743],{"class":512},"     \"evidence\"",[493,1745,1746],{"class":1411},": [], ",[493,1748,1749],{"class":512},"\"trace_ids\"",[493,1751,1752],{"class":1411},": [",[493,1754,1755],{"class":502},"\"tr_01m475tjcngethv5sv\"",[493,1757,111],{"class":1411},[493,1759,1760],{"class":502},"\"tr_01m475tjct11netq93\"",[493,1762,1763],{"class":1411},"],\n",[493,1765,1766,1769,1772,1775,1777,1779,1781,1784,1786,1789,1791,1794,1796,1799,1802,1805,1807,1809,1811,1814,1816,1819],{"class":495,"line":938},[493,1767,1768],{"class":512},"     \"steps\"",[493,1770,1771],{"class":1411},": [{",[493,1773,1774],{"class":512},"\"n\"",[493,1776,757],{"class":1411},[493,1778,630],{"class":512},[493,1780,111],{"class":1411},[493,1782,1783],{"class":512},"\"command\"",[493,1785,757],{"class":1411},[493,1787,1788],{"class":502},"\"expect_text\"",[493,1790,111],{"class":1411},[493,1792,1793],{"class":512},"\"detail\"",[493,1795,757],{"class":1411},[493,1797,1798],{"class":502},"\"",[493,1800,1801],{"class":512},"\\\"",[493,1803,1804],{"class":502},"Nope",[493,1806,1801],{"class":512},[493,1808,1798],{"class":502},[493,1810,111],{"class":1411},[493,1812,1813],{"class":512},"\"outcome\"",[493,1815,757],{"class":1411},[493,1817,1818],{"class":502},"\"fail\"",[493,1820,1383],{"class":1411},[493,1822,1823,1826,1828,1831,1833,1835,1837,1839,1842,1845],{"class":495,"line":944},[493,1824,1825],{"class":512},"                \"duration_ms\"",[493,1827,757],{"class":1411},[493,1829,1830],{"class":512},"813",[493,1832,111],{"class":1411},[493,1834,1749],{"class":512},[493,1836,1752],{"class":1411},[493,1838,1760],{"class":502},[493,1840,1841],{"class":1411},"], ",[493,1843,1844],{"class":512},"\"evidence\"",[493,1846,1847],{"class":1411},": []}]}\n",[493,1849,1850],{"class":495,"line":950},[493,1851,1852],{"class":1411},"  ]\n",[493,1854,1855],{"class":495,"line":956},[493,1856,1857],{"class":1411},"}\n",[10,1859,1860,1861,1863,1864,111,1867,1870,1871,1874,1875,1878,1879,1882,1883,140],{},"Two runs of the same scenario against the same site give the same\n",[19,1862,669],{}," once the fields that name a moment or an id are set aside:\n",[19,1865,1866],{},"started_at",[19,1868,1869],{},"ended_at",", every ",[19,1872,1873],{},"duration_ms",", every trace id, ",[19,1876,1877],{},"run_id","\nand ",[19,1880,1881],{},"pending_confirmation",". A CI job that should fail on anything but\nPASS reads ",[19,1884,1885],{},"summary",[127,1887,1889],{"id":1888},"appjawbscreens-screenshots-across-viewports-and-colour-schemes","app.jawb.screens: screenshots across viewports and colour schemes",[10,1891,1892,1894],{},[19,1893,69],{}," opens each page you name in a fresh incognito tab and takes\none screenshot per viewport and colour scheme. By default that is mobile\nand desktop, light and dark: four PNGs per page.",[383,1896,1898],{"className":487,"code":1897,"language":489,"meta":389,"style":389},"jawb extension install app.jawb.screens\njawb tool call screens.capture --input '{\"base_url\": \"http:\u002F\u002Flocalhost:3000\", \"pages\": [\"\u002F\", \"\u002Fpricing\"]}'\n",[19,1899,1900,1911],{"__ignoreMap":389},[493,1901,1902,1904,1906,1908],{"class":495,"line":496},[493,1903,39],{"class":499},[493,1905,715],{"class":502},[493,1907,718],{"class":502},[493,1909,1910],{"class":502}," app.jawb.screens\n",[493,1912,1913,1915,1917,1919,1922,1924],{"class":495,"line":519},[493,1914,39],{"class":499},[493,1916,503],{"class":502},[493,1918,506],{"class":502},[493,1920,1921],{"class":502}," screens.capture",[493,1923,513],{"class":512},[493,1925,1926],{"class":502}," '{\"base_url\": \"http:\u002F\u002Flocalhost:3000\", \"pages\": [\"\u002F\", \"\u002Fpricing\"]}'\n",[10,1928,1929,1930,757,1933,1383,1936,111,1939,111,1942,1945,1946,1949,1950,433,1952,1954,1955,1958],{},"The files land in ",[19,1931,1932],{},".\u002Fjawb-screens\u002Fscreens\u002F",[19,1934,1935],{},"home-mobile-light.png",[19,1937,1938],{},"home-mobile-dark.png",[19,1940,1941],{},"home-desktop-light.png",[19,1943,1944],{},"home-desktop-dark.png",",\nthe same four for ",[19,1947,1948],{},"pricing",", and ",[19,1951,666],{},[19,1953,669],{},". The\noutput's ",[19,1956,1957],{},"pages"," lists each page with its verdict and its files, as paths\nrelative to the working directory.",[10,1960,1961],{},"Its grants are:",[49,1963,1964,1972,1975,1981,1984],{},[52,1965,1966,1967,433,1969,1971],{},"the origins ",[19,1968,676],{},[19,1970,679],{},";",[52,1973,1974],{},"an incognito tab per page, with no profile, so no cookies or sign-ins;",[52,1976,1977,1978,1971],{},"files under ",[19,1979,1980],{},".\u002Fjawb-screens",[52,1982,1983],{},"at most 500 steps and 900 seconds per run;",[52,1985,1986,1987,1990],{},"the effect ceiling ",[19,1988,1989],{},"act",". It changes the viewport and the\ncolour-scheme emulation and takes screenshots. It never clicks, fills\nor submits.",[10,1992,1993,381],{},[19,1994,1995],{},"app.jawb.screens.capture {base_url, pages?, viewports?, schemes?, name?, out_dir?, step_timeout_ms?}",[49,1997,1998,2003,2012,2031,2041,2050],{},[52,1999,2000,2002],{},[19,2001,1023],{},": the site's address.",[52,2004,2005,2007,2008,2011],{},[19,2006,1957],{},": paths or URLs, 1 to 20 (default ",[19,2009,2010],{},"[\"\u002F\"]","). A page outside the\norigins above is a configuration error (exit 2), and nothing is opened.",[52,2013,2014,757,2017,111,2019,183,2021,2023,2024,2027,2028,322],{},[19,2015,2016],{},"viewports",[19,2018,1193],{},[19,2020,1196],{},[19,2022,1199],{}," such as ",[19,2025,2026],{},"390x844"," (default\n",[19,2029,2030],{},"[\"mobile\", \"desktop\"]",[52,2032,2033,757,2036,978,2038,2040],{},[19,2034,2035],{},"schemes",[19,2037,1203],{},[19,2039,1206],{}," (default both). There are at most 8\nviewport and scheme combinations.",[52,2042,2043,2046,2047,322],{},[19,2044,2045],{},"name",": names the run and its folder (default ",[19,2048,2049],{},"screens",[52,2051,2052,2054,2055,140],{},[19,2053,772],{},": where the files go, inside ",[19,2056,1980],{},[10,2058,2059,2060,140],{},"A page is PASS when all its screenshots were written. A page that does not\nload is UNCERTAIN, with the reason. Exit codes are the ones in\n",[55,2061,484],{"href":2062},"#running-a-tool",[127,2064,2066],{"id":2065},"code-extensions","Code extensions",[10,2068,2069,2070,2073,2074,2077],{},"A ",[14,2071,2072],{},"code extension"," runs its own JavaScript on Node.js, for what a list of\njawb steps cannot do: parse a file, call a local tool, compare results. Its\ntools use the ",[19,2075,2076],{},"exec"," runner, and the package carries a bundle:",[383,2079,2081],{"className":821,"code":2080,"language":823,"meta":389,"style":389},"[runtime]\nnode = \">=22\"\nentry = \"dist\u002Fextension.mjs\"\n\n[[tools]]\nname = \"summarise\"\ndescription = \"Open a page and return its first line\"\neffect = \"act\"\nmax_effect = \"act\"\nrunner = \"exec\"\ninput_schema = \"schemas\u002Fsummarise.input.json\"\noutput_schema = \"schemas\u002Fsummarise.output.json\"\n",[19,2082,2083,2088,2093,2098,2102,2107,2112,2117,2122,2127,2132,2137],{"__ignoreMap":389},[493,2084,2085],{"class":495,"line":496},[493,2086,2087],{},"[runtime]\n",[493,2089,2090],{"class":495,"line":519},[493,2091,2092],{},"node = \">=22\"\n",[493,2094,2095],{"class":495,"line":838},[493,2096,2097],{},"entry = \"dist\u002Fextension.mjs\"\n",[493,2099,2100],{"class":495,"line":844},[493,2101,854],{"emptyLinePlaceholder":853},[493,2103,2104],{"class":495,"line":850},[493,2105,2106],{},"[[tools]]\n",[493,2108,2109],{"class":495,"line":857},[493,2110,2111],{},"name = \"summarise\"\n",[493,2113,2114],{"class":495,"line":863},[493,2115,2116],{},"description = \"Open a page and return its first line\"\n",[493,2118,2119],{"class":495,"line":869},[493,2120,2121],{},"effect = \"act\"\n",[493,2123,2124],{"class":495,"line":875},[493,2125,2126],{},"max_effect = \"act\"\n",[493,2128,2129],{"class":495,"line":881},[493,2130,2131],{},"runner = \"exec\"\n",[493,2133,2134],{"class":495,"line":887},[493,2135,2136],{},"input_schema = \"schemas\u002Fsummarise.input.json\"\n",[493,2138,2139],{"class":495,"line":893},[493,2140,2141],{},"output_schema = \"schemas\u002Fsummarise.output.json\"\n",[10,2143,2144,2145,2148],{},"The entry module exports ",[19,2146,2147],{},"activate(ctx)"," and registers each tool the\nmanifest declares:",[383,2150,2154],{"className":2151,"code":2152,"language":2153,"meta":389,"style":389},"language-js shiki shiki-themes github-light github-dark","export function activate(ctx) {\n  ctx.registerTool(\"summarise\", async (input, run) => {\n    const opened = await run.jawb.open(input.url, { incognito: true });\n    const t = opened.result.tab;\n    const read = await run.jawb.tab(t).read({ format: \"text\" });\n    await run.jawb.tab(t).close();\n    return { first_line: read.result.content.split(\"\\n\")[0] };\n  });\n}\n","js",[19,2155,2156,2178,2214,2242,2254,2283,2300,2328,2333],{"__ignoreMap":389},[493,2157,2158,2162,2165,2168,2171,2175],{"class":495,"line":496},[493,2159,2161],{"class":2160},"szBVR","export",[493,2163,2164],{"class":2160}," function",[493,2166,2167],{"class":499}," activate",[493,2169,2170],{"class":1411},"(",[493,2172,2174],{"class":2173},"s4XuR","ctx",[493,2176,2177],{"class":1411},") {\n",[493,2179,2180,2183,2186,2188,2191,2193,2196,2198,2201,2203,2205,2208,2211],{"class":495,"line":519},[493,2181,2182],{"class":1411},"  ctx.",[493,2184,2185],{"class":499},"registerTool",[493,2187,2170],{"class":1411},[493,2189,2190],{"class":502},"\"summarise\"",[493,2192,111],{"class":1411},[493,2194,2195],{"class":2160},"async",[493,2197,586],{"class":1411},[493,2199,2200],{"class":2173},"input",[493,2202,111],{"class":1411},[493,2204,124],{"class":2173},[493,2206,2207],{"class":1411},") ",[493,2209,2210],{"class":2160},"=>",[493,2212,2213],{"class":1411}," {\n",[493,2215,2216,2219,2222,2225,2228,2231,2233,2236,2239],{"class":495,"line":838},[493,2217,2218],{"class":2160},"    const",[493,2220,2221],{"class":512}," opened",[493,2223,2224],{"class":2160}," =",[493,2226,2227],{"class":2160}," await",[493,2229,2230],{"class":1411}," run.jawb.",[493,2232,970],{"class":499},[493,2234,2235],{"class":1411},"(input.url, { incognito: ",[493,2237,2238],{"class":512},"true",[493,2240,2241],{"class":1411}," });\n",[493,2243,2244,2246,2249,2251],{"class":495,"line":844},[493,2245,2218],{"class":2160},[493,2247,2248],{"class":512}," t",[493,2250,2224],{"class":2160},[493,2252,2253],{"class":1411}," opened.result.tab;\n",[493,2255,2256,2258,2261,2263,2265,2267,2270,2273,2276,2279,2281],{"class":495,"line":850},[493,2257,2218],{"class":2160},[493,2259,2260],{"class":512}," read",[493,2262,2224],{"class":2160},[493,2264,2227],{"class":2160},[493,2266,2230],{"class":1411},[493,2268,2269],{"class":499},"tab",[493,2271,2272],{"class":1411},"(t).",[493,2274,2275],{"class":499},"read",[493,2277,2278],{"class":1411},"({ format: ",[493,2280,1710],{"class":502},[493,2282,2241],{"class":1411},[493,2284,2285,2288,2290,2292,2294,2297],{"class":495,"line":857},[493,2286,2287],{"class":2160},"    await",[493,2289,2230],{"class":1411},[493,2291,2269],{"class":499},[493,2293,2272],{"class":1411},[493,2295,2296],{"class":499},"close",[493,2298,2299],{"class":1411},"();\n",[493,2301,2302,2305,2308,2311,2313,2315,2318,2320,2323,2325],{"class":495,"line":863},[493,2303,2304],{"class":2160},"    return",[493,2306,2307],{"class":1411}," { first_line: read.result.content.",[493,2309,2310],{"class":499},"split",[493,2312,2170],{"class":1411},[493,2314,1798],{"class":502},[493,2316,2317],{"class":512},"\\n",[493,2319,1798],{"class":502},[493,2321,2322],{"class":1411},")[",[493,2324,622],{"class":512},[493,2326,2327],{"class":1411},"] };\n",[493,2329,2330],{"class":495,"line":869},[493,2331,2332],{"class":1411},"  });\n",[493,2334,2335],{"class":495,"line":875},[493,2336,1857],{"class":1411},[10,2338,2339,2342,2343,2345,2346,2349,2350,2353,2354,322],{},[19,2340,2341],{},"run.jawb.*"," is jawb's API for the call: each method is one request to\n",[19,2344,35],{},", made by the CLI for this run, so the run's limits, origins, policy,\nconfirmations and trace apply to it. A call after the tool has returned is\nrefused (",[19,2347,2348],{},"no_run","). The tool's return value is checked against its\n",[19,2351,2352],{},"output_schema"," before the call ends (",[19,2355,2356],{},"invalid_output",[10,2358,2359,2362,2363,1383,2366,111,2369,111,2372,2375,2376,2378,2379,2381,2382,2385,2386,2388,2389,140],{},[14,2360,2361],{},"Code runs with your full access."," It is a Node.js process with your user\naccount's rights, not a sandbox: it can read your files and reach the\nnetwork on its own. The manifest's grants (",[19,2364,2365],{},"[matches]",[19,2367,2368],{},"browser_sessions",[19,2370,2371],{},"[limits]",[19,2373,2374],{},"max_effect",") bind what it asks jawb to do\nthrough ",[19,2377,2341],{},", and jawb records and gates those calls, but for the\ncode itself they are advisory: with your account's access it could read\njawb's own files or drive a browser without jawb. Install code only from a\npublisher you trust. So installing a code extension says so (\"runs code on\nthis computer with full access to your user account\"), and only an approval\nyour operating system verifies (Windows Hello, Touch ID or your password)\ninstalls it; a typed ",[19,2380,380],{}," alone is refused\n(",[19,2383,2384],{},"code_install_needs_verification","). Any change to its files asks again.\n",[19,2387,167],{}," marks it ",[19,2390,2391],{},"[runs code: full user access]",[10,2393,2394],{},"How the CLI runs it:",[49,2396,2397,2414,2424,2459,2480],{},[52,2398,2399,2402,2403,2406,2407,2410,2411,140],{},[14,2400,2401],{},"Node.js 22 or later"," must be on your ",[19,2404,2405],{},"PATH"," (or set ",[19,2408,2409],{},"JAWB_NODE",");\notherwise the call exits 2 with ",[19,2412,2413],{},"runtime_missing",[52,2415,2416,2419,2420,2423],{},[14,2417,2418],{},"Checked first."," Before it starts the code, the CLI checks every file\nagainst the digests you approved, and refuses with ",[19,2421,2422],{},"package_modified","\nwhen one changed.",[52,2425,2426,2429,2430,2432,2433,111,2436,433,2439,2442,2443,2446,2447,2450,2451,2454,2455,2458],{},[14,2427,2428],{},"A clean environment."," The process gets only ",[19,2431,2405],{}," (and, on Windows,\n",[19,2434,2435],{},"SystemRoot",[19,2437,2438],{},"TEMP",[19,2440,2441],{},"TMP","): no ",[19,2444,2445],{},"JAWB_*"," variable and no daemon\ntoken. It runs in its own working directory under\n",[19,2448,2449],{},"%LOCALAPPDATA%\\jawb-exthost"," (Windows) or ",[19,2452,2453],{},"~\u002F.cache\u002Fjawb-exthost",",\nwhich ",[19,2456,2457],{},"jawb extension remove"," deletes.",[52,2460,2461,2464,2465,2467,2468,2471,2472,2475,2476,2479],{},[14,2462,2463],{},"One process per call"," for ",[19,2466,25],{},"; ",[19,2469,2470],{},"jawb mcp"," keeps one per\nextension for the session. A call that passes ",[19,2473,2474],{},"[limits] max_run_seconds","\nis stopped, and the process is killed together with everything it\nstarted. ",[19,2477,2478],{},"[limits] memory_mb"," caps its heap.",[52,2481,2482,2485],{},[19,2483,2484],{},"console.log"," goes to the CLI's log, never into the tool's output or the\ntrace.",[10,2487,2488,2489,2492,2493,2495,2496,2498],{},"Not yet: hooks (",[19,2490,2491],{},"ctx.registerHook"," throws until #198), and activation\nconditions beyond \"a tool was called\". Code extensions need ",[19,2494,35],{}," at API\nlevel 35 and a ",[19,2497,39],{}," CLI after 0.1.1.",[127,2500,2502],{"id":2501},"publish-your-extension-on-jawb-hub","Publish your extension on jawb Hub",[10,2504,2505,2506,2512,2513,2518,2519,2522,2523,2528,2529,2534,2535,2540,2541,140],{},"Community extensions are listed on\n",[55,2507,2511],{"href":2508,"rel":2509},"https:\u002F\u002Fgithub.com\u002F4hum-ai\u002Fjawb-hub",[2510],"nofollow","jawb Hub",", a public GitHub\nrepository, and shown on ",[55,2514,2517],{"href":2515,"rel":2516},"https:\u002F\u002Fjawb.app\u002Fextensions",[2510],"jawb.app\u002Fextensions",".\n",[14,2520,2521],{},"Listed means the exact bytes passed jawb Hub's automated checks."," It is\nnot a review, a signature or a warranty: jawb does not vouch for the code.\nThe ",[55,2524,2527],{"href":2525,"rel":2526},"https:\u002F\u002Fgithub.com\u002F4hum-ai\u002Fjawb-hub\u002Fblob\u002Fmain\u002FTERMS.md",[2510],"listing terms","\napply. The author guides live there too: a tutorial,\n",[55,2530,2533],{"href":2531,"rel":2532},"https:\u002F\u002Fgithub.com\u002F4hum-ai\u002Fjawb-hub\u002Fblob\u002Fmain\u002Fdocs\u002Ftutorial.md",[2510],"Build and list your first extension",",\nthe ",[55,2536,2539],{"href":2537,"rel":2538},"https:\u002F\u002Fgithub.com\u002F4hum-ai\u002Fjawb-hub\u002Fblob\u002Fmain\u002Fdocs\u002Fmanifest.md",[2510],"manifest reference",",\nand a template to copy, ",[55,2542,2545],{"href":2543,"rel":2544},"https:\u002F\u002Fgithub.com\u002F4hum-ai\u002Fjawb-hub\u002Ftree\u002Fmain\u002Fexamples\u002Fsite-screens",[2510],[19,2546,2547],{},"examples\u002Fsite-screens",[2549,2550,2551,2560,2596,2606],"ol",{},[52,2552,2553,2556,2557,2559],{},[14,2554,2555],{},"Host your extension yourself",", as a release ",[19,2558,233],{}," (a GitHub\nrelease asset, for example) or an npm package. Your code stays in your\nrepository, under your licence.",[52,2561,2562,2565],{},[14,2563,2564],{},"Prove you own its id.",[49,2566,2567,2574],{},[52,2568,2569,2570,2573],{},"For ",[19,2571,2572],{},"io.github.\u003Cyou>.\u003Cname>",", your GitHub account is the proof.",[52,2575,2576,2577,2580,2581,2584,2585,2588,2589,2592,2593,140],{},"For a domain id (",[19,2578,2579],{},"com.example.hello"," names ",[19,2582,2583],{},"example.com","), publish\n",[19,2586,2587],{},"github:\u003Cyour login>",", either in\n",[19,2590,2591],{},"https:\u002F\u002Fexample.com\u002F.well-known\u002Fjawb-hub.txt"," or as a DNS TXT record\n",[19,2594,2595],{},"_jawb-hub.example.com",[52,2597,2598,2601,2602,2605],{},[14,2599,2600],{},"Open a pull request"," that adds one file, ",[19,2603,2604],{},"listings\u002F\u003Cid>.toml",", with\nthe id, its owners, a homepage, and for each version its source and the\nsha256 of the exact file.",[52,2607,2608,2611,2634,2637],{},[14,2609,2610],{},"The checks run on the pull request:",[49,2612,2613,2616,2619,2625,2628,2631],{},[52,2614,2615],{},"fetch the package from its source and compare its sha256;",[52,2617,2618],{},"the package rules;",[52,2620,2621,2622,2624],{},"the manifest, as ",[19,2623,35],{}," checks it;",[52,2626,2627],{},"hidden or bidi characters in anything a model reads;",[52,2629,2630],{},"the never-list;",[52,2632,2633],{},"ownership of the id.",[2635,2636],"br",{},"A maintainer merges a green pull request without reviewing your code, and\nthe listing appears on jawb.app. A listed version never changes: publish\na new version instead.",[10,2639,2640,2641,2644,2645,404,2647,433,2650,2653,2654,322],{},"Once a listing is merged, ",[19,2642,2643],{},"jawb extension install \u003Cid>"," installs it from\njawb's signed index, labelled ",[236,2646,238],{},[19,2648,2649],{},"install \u003Curl>",[19,2651,2652],{},"install --file","\ntake the same bytes from anywhere (see\n",[55,2655,247],{"href":246},[127,2657,2659],{"id":2658},"what-comes-later","What comes later",[10,2661,2662],{},"These parts of the extension design are planned, not built.",[49,2664,2665,2688,2694,2706,2712,2722,2734],{},[52,2666,2667,413,2670,2673,2674,586,2677,2679,2680,2683,2684,2687],{},[14,2668,2669],{},"More shapes.",[236,2671,2672],{},"Site tool packs"," (a script in the matching tab, in its\nown isolated world) and ",[236,2675,2676],{},"app connectors or API tools",[19,2678,35],{}," adds a\nstored secret at the network layer; the extension never sees it). A\nstored secret will carry the domains it may be sent to, so an extension\ncannot move it elsewhere. Two more shapes are reserved: ",[236,2681,2682],{},"policy packs",",\nwhich can only make jawb's decisions stricter, and ",[236,2685,2686],{},"readers",", which\nturn jawb's own view of a page into structured data.",[52,2689,2690,2693],{},[14,2691,2692],{},"More third-party sources."," Installing from npm and from a git\nrepository, besides a file and a URL (built, waiting for jawb's signed\nindex).",[52,2695,2696,2699,2700,2702,2703,2705],{},[14,2697,2698],{},"jawb's signed index."," jawb Hub's listings will reach ",[19,2701,35],{}," in a\nsigned index with a short expiry, which also carries a revocation list,\nby version or by the package's sha256. A revoked package is switched off\nand its data kept. An out-of-date index stops new installs but never\nblocks browsing. ",[19,2704,35],{}," already enforces all of this; jawb does not\npublish the index yet.",[52,2707,2708,2711],{},[14,2709,2710],{},"The desktop app."," Discovering, installing and removing extensions in\nthe jawb desktop app, from the same signed catalogue the CLI uses.",[52,2713,2714,2717,2718,2721],{},[14,2715,2716],{},"Hooks."," Code extensions subscribing to what happens in jawb (a page\nloaded, an action done, a tool called), from the same events\n",[19,2719,2720],{},"jawb trace --follow --json"," shows.",[52,2723,2724,2727,2728,2733],{},[14,2725,2726],{},"An isolated host."," A WebAssembly Component host\n(",[55,2729,2732],{"href":2730,"rel":2731},"https:\u002F\u002Fwasmtime.dev\u002F",[2510],"Wasmtime",") where extension code gets only what\nits manifest grants, with per-plugin quotas, for extensions that do not\nneed full access.",[52,2735,2736,2739],{},[14,2737,2738],{},"Free and paid."," Free and paid extensions are planned. jawb itself is\nfree for personal developers; business and team use will need a paid\nlicence.",[426,2741,2743],{"id":2742},"what-jawb-will-never-list","What jawb will never list",[49,2745,2746,2749,2752,2755,2758],{},[52,2747,2748],{},"LinkedIn data extraction or outreach tools. LinkedIn's terms name\nbrowser add-ons.",[52,2750,2751],{},"Coupon auto-appliers at checkout.",[52,2753,2754],{},"CAPTCHA solvers, and anything that evades rate limits or bot defences.",[52,2756,2757],{},"Generators that pass a second factor unattended.",[52,2759,2760],{},"AI sidebar clones: your agent's own model does that job.",[10,2762,2763],{},"The catalogue also refuses rules that loosen anything, hooks that change\nhow the browser launches or what every page sees, native binaries, and\nextension code inside the jawb desktop app.",[10,2765,2766,2767,2771],{},"See ",[55,2768,2770],{"href":2769},"\u002Fdocs\u002Froadmap","Roadmap and status"," for what is built and what is\nplanned.",[2773,2774,2775],"style",{},"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);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":389,"searchDepth":519,"depth":519,"links":2777},[2778,2779,2782,2783,2789,2790,2791,2792],{"id":129,"depth":519,"text":130},{"id":362,"depth":519,"text":363,"children":2780},[2781],{"id":428,"depth":838,"text":247},{"id":483,"depth":519,"text":484},{"id":650,"depth":519,"text":651,"children":2784},[2785,2786,2787,2788],{"id":724,"depth":838,"text":725},{"id":806,"depth":838,"text":807},{"id":1272,"depth":838,"text":1273},{"id":1368,"depth":838,"text":1369},{"id":1888,"depth":519,"text":1889},{"id":2065,"depth":519,"text":2066},{"id":2501,"depth":519,"text":2502},{"id":2658,"depth":519,"text":2659,"children":2793},[2794],{"id":2742,"depth":838,"text":2743},"jawb extensions: the built-in app.jawb.* extensions, jawb extension and jawb tool call, consent, runs and their limits, app.jawb.uat and app.jawb.screens, and publishing on jawb Hub.","md",{},null,"\u002Fdocs\u002Fextensions",{"title":5,"description":2795},"docs\u002F11.extensions","4-4EVNrn9cV3mcT5gIWB1Jc3UrHyyzSIiwGWlFNnJ-g",[2804],{"title":2805,"path":2806,"stem":2807,"children":2808},"Documentation","\u002Fdocs","docs\u002F1.index",[2809,2810,2814,2815,2817,2839,2878,2892,2896,2900,2904,2908],{"title":2805,"path":2806,"stem":2807},{"title":2811,"path":2812,"stem":2813},"Protocol adapters","\u002Fdocs\u002Fprotocol","docs\u002F10.protocol",{"title":5,"path":2799,"stem":2801},{"title":2770,"path":2769,"stem":2816},"docs\u002F12.roadmap",{"title":2818,"path":2819,"stem":2820,"children":2821},"Getting started","\u002Fdocs\u002Fgetting-started","docs\u002F2.getting-started\u002F1.index",[2822,2823,2827,2831,2835],{"title":2818,"path":2819,"stem":2820},{"title":2824,"path":2825,"stem":2826},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","docs\u002F2.getting-started\u002F2.installation",{"title":2828,"path":2829,"stem":2830},"Desktop app","\u002Fdocs\u002Fgetting-started\u002Fdesktop-app","docs\u002F2.getting-started\u002F3.desktop-app",{"title":2832,"path":2833,"stem":2834},"Running the daemon","\u002Fdocs\u002Fgetting-started\u002Frunning-the-daemon","docs\u002F2.getting-started\u002F4.running-the-daemon",{"title":2836,"path":2837,"stem":2838},"Using the CLI","\u002Fdocs\u002Fgetting-started\u002Fusing-the-cli","docs\u002F2.getting-started\u002F5.using-the-cli",{"title":2840,"path":2841,"stem":2842,"children":2843},"CLI reference","\u002Fdocs\u002Fcli","docs\u002F3.cli\u002F1.index",[2844,2845,2848,2852,2856,2860,2864,2868,2872,2874],{"title":2840,"path":2841,"stem":2842},{"title":2846,"path":350,"stem":2847},"JSON envelope and exit codes","docs\u002F3.cli\u002F10.json-and-exit-codes",{"title":2849,"path":2850,"stem":2851},"jawb status","\u002Fdocs\u002Fcli\u002Fstatus","docs\u002F3.cli\u002F2.status",{"title":2853,"path":2854,"stem":2855},"Tabs, profiles and sessions","\u002Fdocs\u002Fcli\u002Ftabs-and-profiles","docs\u002F3.cli\u002F3.tabs-and-profiles",{"title":2857,"path":2858,"stem":2859},"jawb observe [\u003Curl>] [--full] [--interactive-only] [--js]","\u002Fdocs\u002Fcli\u002Fobserve","docs\u002F3.cli\u002F4.observe",{"title":2861,"path":2862,"stem":2863},"jawb read [--format md|text|json] [--element \u003Cid>] [--full] [--js]","\u002Fdocs\u002Fcli\u002Fread","docs\u002F3.cli\u002F5.read",{"title":2865,"path":2866,"stem":2867},"Act commands","\u002Fdocs\u002Fcli\u002Fact","docs\u002F3.cli\u002F6.act",{"title":2869,"path":2870,"stem":2871},"See commands","\u002Fdocs\u002Fcli\u002Fsee","docs\u002F3.cli\u002F7.see",{"title":370,"path":369,"stem":2873},"docs\u002F3.cli\u002F8.policy",{"title":2875,"path":2876,"stem":2877},"Install lifecycle and profile settings","\u002Fdocs\u002Fcli\u002Flifecycle","docs\u002F3.cli\u002F9.lifecycle",{"title":2879,"path":2880,"stem":2881,"children":2882},"SDK reference","\u002Fdocs\u002Fsdk","docs\u002F4.sdk\u002F1.index",[2883,2884,2888],{"title":2879,"path":2880,"stem":2881},{"title":2885,"path":2886,"stem":2887},"Rust SDK — jawb-sdk-rust","\u002Fdocs\u002Fsdk\u002Frust-sdk","docs\u002F4.sdk\u002F2.rust-sdk",{"title":2889,"path":2890,"stem":2891},"Website SDK — @4hum-ai\u002Fjawb-sdk","\u002Fdocs\u002Fsdk\u002Fwebsite-sdk","docs\u002F4.sdk\u002F3.website-sdk",{"title":2893,"path":2894,"stem":2895},"Configuration","\u002Fdocs\u002Fconfig","docs\u002F5.config",{"title":2897,"path":2898,"stem":2899},"WebMCP","\u002Fdocs\u002Fwebmcp","docs\u002F6.webmcp",{"title":2901,"path":2902,"stem":2903},"Agents","\u002Fdocs\u002Fagents","docs\u002F7.agents",{"title":2905,"path":2906,"stem":2907},"MCP server","\u002Fdocs\u002Fmcp","docs\u002F8.mcp",{"title":2909,"path":2910,"stem":2911},"Security and trust","\u002Fdocs\u002Fsecurity","docs\u002F9.security",1792595702263]