[{"data":1,"prerenderedAt":580},["ShallowReactive",2],{"docs-/docs/development/dependencies":3},{"id":4,"title":5,"body":6,"description":573,"extension":574,"meta":575,"navigation":115,"path":576,"seo":577,"stem":578,"__hash__":579},"docs/docs/development/dependencies.md","Dependencies",{"type":7,"value":8,"toc":563},"minimark",[9,13,31,45,52,62,72,95,135,160,166,174,258,277,348,363,367,370,434,437,441,444,450,501,507,511,522,544,548,559],[10,11,5],"h1",{"id":12},"dependencies",[14,15,16,17,21,22,25,26,30],"p",{},"Your tool can use third-party libraries. You declare them in a standard manifest at the root of your repo — ",[18,19,20],"code",{},"requirements.txt"," for Python, ",[18,23,24],{},"package.json"," for JavaScript — and the sandbox installs them for you. There's no separate \"add a library\" step: the file ",[27,28,29],"em",{},"is"," the source of truth.",[14,32,33,34,39,40,44],{},"This page covers both languages and exactly when installation happens. For where these files live in your repo, see ",[35,36,38],"a",{"href":37},"/docs/development/entry-point","Entry point","; for editing them, see the ",[35,41,43],{"href":42},"/docs/development/ide","IDE",".",[46,47,49,50],"h2",{"id":48},"python-requirementstxt","Python — ",[18,51,20],{},[14,53,54,55,57,58,61],{},"Put a ",[18,56,20],{}," next to your ",[18,59,60],{},"main.py",". It uses the normal pip format, one package per line:",[63,64,69],"pre",{"className":65,"code":67,"language":68},[66],"language-text","requests==2.32.3\npandas>=2.0\nPillow\n","text",[18,70,67],{"__ignoreMap":71},"",[14,73,74,75,79,80,88,89,91,92,94],{},"The sandbox creates a ",[76,77,78],"strong",{},"dedicated virtual environment for your tool"," (using ",[35,81,85],{"href":82,"rel":83},"https://docs.astral.sh/uv/",[84],"nofollow",[18,86,87],{},"uv"," under the hood) and installs everything in ",[18,90,20],{}," into it. You never manage the venv yourself — just edit the file. Import the packages in ",[18,93,60],{}," as usual:",[63,96,100],{"className":97,"code":98,"language":99,"meta":71,"style":71},"language-python shiki shiki-themes github-light github-dark","import requests\n\ndef process(input, settings):\n    r = requests.get(input[\"url\"])\n    return { \"status\": r.status_code }\n","python",[18,101,102,110,117,123,129],{"__ignoreMap":71},[103,104,107],"span",{"class":105,"line":106},"line",1,[103,108,109],{},"import requests\n",[103,111,113],{"class":105,"line":112},2,[103,114,116],{"emptyLinePlaceholder":115},true,"\n",[103,118,120],{"class":105,"line":119},3,[103,121,122],{},"def process(input, settings):\n",[103,124,126],{"class":105,"line":125},4,[103,127,128],{},"    r = requests.get(input[\"url\"])\n",[103,130,132],{"class":105,"line":131},5,[103,133,134],{},"    return { \"status\": r.status_code }\n",[136,137,138],"blockquote",{},[14,139,140,141,144,145,148,149,152,153,156,157,159],{},"The ",[18,142,143],{},"artifuncs"," SDK (",[18,146,147],{},"get_file_content",", ",[18,150,151],{},"log",", …) is ",[76,154,155],{},"pre-installed"," in every Python tool. Don't add it to ",[18,158,20],{}," — it's always available.",[46,161,163,164],{"id":162},"javascript-packagejson","JavaScript — ",[18,165,24],{},[14,167,54,168,170,171,173],{},[18,169,24],{}," at the repo root and list packages under ",[18,172,12],{},":",[63,175,179],{"className":176,"code":177,"language":178,"meta":71,"style":71},"language-json shiki shiki-themes github-light github-dark","{\n  \"name\": \"my-tool\",\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"lodash\": \"^4.17.21\",\n    \"date-fns\": \"3.6.0\"\n  }\n}\n","json",[18,180,181,187,203,215,223,235,246,252],{"__ignoreMap":71},[103,182,183],{"class":105,"line":106},[103,184,186],{"class":185},"sVt8B","{\n",[103,188,189,193,196,200],{"class":105,"line":112},[103,190,192],{"class":191},"sj4cs","  \"name\"",[103,194,195],{"class":185},": ",[103,197,199],{"class":198},"sZZnC","\"my-tool\"",[103,201,202],{"class":185},",\n",[103,204,205,208,210,213],{"class":105,"line":119},[103,206,207],{"class":191},"  \"type\"",[103,209,195],{"class":185},[103,211,212],{"class":198},"\"module\"",[103,214,202],{"class":185},[103,216,217,220],{"class":105,"line":125},[103,218,219],{"class":191},"  \"dependencies\"",[103,221,222],{"class":185},": {\n",[103,224,225,228,230,233],{"class":105,"line":131},[103,226,227],{"class":191},"    \"lodash\"",[103,229,195],{"class":185},[103,231,232],{"class":198},"\"^4.17.21\"",[103,234,202],{"class":185},[103,236,238,241,243],{"class":105,"line":237},6,[103,239,240],{"class":191},"    \"date-fns\"",[103,242,195],{"class":185},[103,244,245],{"class":198},"\"3.6.0\"\n",[103,247,249],{"class":105,"line":248},7,[103,250,251],{"class":185},"  }\n",[103,253,255],{"class":105,"line":254},8,[103,256,257],{"class":185},"}\n",[14,259,260,261,268,269,272,273,276],{},"The sandbox installs them with ",[35,262,265],{"href":263,"rel":264},"https://pnpm.io/",[84],[18,266,267],{},"pnpm"," into a ",[18,270,271],{},"node_modules"," folder next to your ",[18,274,275],{},"index.js",". Require/import them as normal:",[63,278,282],{"className":279,"code":280,"language":281,"meta":71,"style":71},"language-js shiki shiki-themes github-light github-dark","import { chunk } from 'lodash'\n\nexport function process(input, settings) {\n    return { batches: chunk(input.items, settings.size) }\n}\n","js",[18,283,284,299,303,330,344],{"__ignoreMap":71},[103,285,286,290,293,296],{"class":105,"line":106},[103,287,289],{"class":288},"szBVR","import",[103,291,292],{"class":185}," { chunk } ",[103,294,295],{"class":288},"from",[103,297,298],{"class":198}," 'lodash'\n",[103,300,301],{"class":105,"line":112},[103,302,116],{"emptyLinePlaceholder":115},[103,304,305,308,311,315,318,322,324,327],{"class":105,"line":119},[103,306,307],{"class":288},"export",[103,309,310],{"class":288}," function",[103,312,314],{"class":313},"sScJk"," process",[103,316,317],{"class":185},"(",[103,319,321],{"class":320},"s4XuR","input",[103,323,148],{"class":185},[103,325,326],{"class":320},"settings",[103,328,329],{"class":185},") {\n",[103,331,332,335,338,341],{"class":105,"line":125},[103,333,334],{"class":288},"    return",[103,336,337],{"class":185}," { batches: ",[103,339,340],{"class":313},"chunk",[103,342,343],{"class":185},"(input.items, settings.size) }\n",[103,345,346],{"class":105,"line":131},[103,347,257],{"class":185},[136,349,350],{},[14,351,352,353,356,357,360,361,44],{},"Logging is provided via ",[18,354,355],{},"require('artifuncs-log')"," — it's injected by the sandbox, so ",[76,358,359],{},"don't"," add it to ",[18,362,24],{},[46,364,366],{"id":365},"when-dependencies-are-installed","When dependencies are installed",[14,368,369],{},"Installation is automatic, but it's worth knowing the timing so first runs don't surprise you:",[371,372,373,386],"table",{},[374,375,376],"thead",{},[377,378,379,383],"tr",{},[380,381,382],"th",{},"When",[380,384,385],{},"What happens",[387,388,389,400,410],"tbody",{},[377,390,391,397],{},[392,393,394],"td",{},[76,395,396],{},"First run after deploy",[392,398,399],{},"The sandbox does a full install of everything in your manifest. Dependency-heavy tools can take a few seconds (or longer) the first time.",[377,401,402,407],{},[392,403,404],{},[76,405,406],{},"Later runs",[392,408,409],{},"The installed environment is reused — install is skipped entirely, so runs are fast.",[377,411,412,423],{},[392,413,414],{},[76,415,416,417,419,420,422],{},"You edit ",[18,418,20],{}," / ",[18,421,24],{}," in the IDE",[392,424,425,426,428,429,433],{},"Saving the file triggers a reinstall of just the dependencies (the venv / ",[18,427,271],{}," isn't rebuilt from scratch). You'll see install output in the ",[35,430,432],{"href":431},"/docs/development/ide#log-panel","log panel"," and a success or error toast.",[14,435,436],{},"The decision to install vs. skip is based purely on whether the environment already exists — there's no per-package change tracking. Editing the manifest is what forces a refresh.",[46,438,440],{"id":439},"pinning-versions","Pinning versions",[14,442,443],{},"You can use any version specifier your package manager understands:",[63,445,448],{"className":446,"code":447,"language":68},[66],"# requirements.txt\nnumpy==1.26.4      # exact — recommended for published tools\nhttpx>=0.27        # minimum\nscipy              # latest at install time\n",[18,449,447],{"__ignoreMap":71},[63,451,453],{"className":176,"code":452,"language":178,"meta":71,"style":71},"// package.json\n\"dependencies\": {\n  \"zod\": \"3.23.8\",     // exact\n  \"axios\": \"^1.7.0\"    // compatible range\n}\n",[18,454,455,461,468,484,497],{"__ignoreMap":71},[103,456,457],{"class":105,"line":106},[103,458,460],{"class":459},"sJ8bj","// package.json\n",[103,462,463,466],{"class":105,"line":112},[103,464,465],{"class":198},"\"dependencies\"",[103,467,222],{"class":185},[103,469,470,473,475,478,481],{"class":105,"line":119},[103,471,472],{"class":191},"  \"zod\"",[103,474,195],{"class":185},[103,476,477],{"class":198},"\"3.23.8\"",[103,479,480],{"class":185},",     ",[103,482,483],{"class":459},"// exact\n",[103,485,486,489,491,494],{"class":105,"line":125},[103,487,488],{"class":191},"  \"axios\"",[103,490,195],{"class":185},[103,492,493],{"class":198},"\"^1.7.0\"",[103,495,496],{"class":459},"    // compatible range\n",[103,498,499],{"class":105,"line":131},[103,500,257],{"class":185},[14,502,503,506],{},[76,504,505],{},"Pin exact versions before you publish."," A published tool is installed fresh in each visitor's sandbox; an unpinned dependency can resolve to a newer, breaking release later and silently change how your tool behaves.",[46,508,510],{"id":509},"any-package","Any package?",[14,512,513,514,517,518,521],{},"There's no allowlist on libraries — you can install anything published to ",[76,515,516],{},"PyPI"," (Python) or the ",[76,519,520],{},"npm registry"," (JavaScript). Packages are downloaded from those registries when your tool is set up.",[14,523,524,525,528,529,539,540,543],{},"This is separate from network access ",[27,526,527],{},"at runtime",". Once your tool is running, the sandbox blocks outbound network except for the external APIs you declare under ",[35,530,532,535,536],{"href":531},"/docs/development/artifuncs-json#apis",[18,533,534],{},"apis"," in ",[18,537,538],{},"artifuncs.json",". So a library installs fine, but if it tries to reach a service over the network ",[27,541,542],{},"while your tool runs",", that call is blocked unless the domain is allowlisted.",[46,545,547],{"id":546},"when-an-install-fails","When an install fails",[14,549,550,551,419,553,555,556,558],{},"If a package name is misspelled, a pinned version doesn't exist, or the registry can't be reached, the install fails and the ",[18,552,87],{},[18,554,267],{}," error is streamed to the ",[35,557,432],{"href":431}," (and shown as a toast in the IDE). The tool won't run until the manifest is fixed — correct the file and save again to retry.",[560,561,562],"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 .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":71,"searchDepth":112,"depth":112,"links":564},[565,567,569,570,571,572],{"id":48,"depth":112,"text":566},"Python — requirements.txt",{"id":162,"depth":112,"text":568},"JavaScript — package.json",{"id":365,"depth":112,"text":366},{"id":439,"depth":112,"text":440},{"id":509,"depth":112,"text":510},{"id":546,"depth":112,"text":547},"How third-party libraries work — declare them in requirements.txt or package.json, and the sandbox installs them automatically.","md",{},"/docs/development/dependencies",{"title":5,"description":573},"docs/development/dependencies","mgInwD7hI-dOqRZVXIdUvrG5s9YMNyHupQavETXg56s",1781004913741]