[{"data":1,"prerenderedAt":412},["ShallowReactive",2],{"-docs-guide-custom-runner":3,"-docs-guide-custom-runner-surround":399},{"id":4,"title":5,"body":6,"description":389,"extension":390,"links":391,"meta":392,"navigation":393,"path":395,"seo":396,"stem":397,"__hash__":398},"docs\u002Fdocs\u002F2.guide\u002F8.custom-runner.md","How to configure a custom model runner",{"type":7,"value":8,"toc":381},"minimark",[9,13,18,36,40,51,86,96,99,159,162,166,169,177,180,189,193,204,228,231,263,274,278,281,305,308,334,346,350,377],[10,11,12],"p",{},"A custom runner is any local command that reads a rendered prompt and writes model output to stdout. The Rust agent handles claims, temporary prompt files, process timeouts, heartbeats, and result submission.",[14,15,17],"h2",{"id":16},"prerequisites","Prerequisites",[19,20,21,25,28],"ul",{},[22,23,24],"li",{},"The agent is installed and enrolled.",[22,26,27],{},"The model code is enabled for the project.",[22,29,30,31,35],{},"The command works under a POSIX ",[32,33,34],"code",{},"sh -c"," shell. On Windows, use Git Bash or Windows Subsystem for Linux.",[14,37,39],{"id":38},"add-a-model-binding","Add a model binding",[10,41,42,43,46,47,50],{},"Add a ",[32,44,45],{},"[[model]]"," table to ",[32,48,49],{},"~\u002F.thespider\u002Fconfig.toml",":",[52,53,58],"pre",{"className":54,"code":55,"language":56,"meta":57,"style":57},"language-toml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","[[model]]\ncode = \"sonnet\"\ncommand = \"claude --print \u003C {prompt_path}\"\ntimeout_seconds = 900\n","toml","",[32,59,60,68,74,80],{"__ignoreMap":57},[61,62,65],"span",{"class":63,"line":64},"line",1,[61,66,67],{},"[[model]]\n",[61,69,71],{"class":63,"line":70},2,[61,72,73],{},"code = \"sonnet\"\n",[61,75,77],{"class":63,"line":76},3,[61,78,79],{},"command = \"claude --print \u003C {prompt_path}\"\n",[61,81,83],{"class":63,"line":82},4,[61,84,85],{},"timeout_seconds = 900\n",[10,87,88,89,91,92,95],{},"The ",[32,90,32],{}," must match the server model catalog. ",[32,93,94],{},"timeout_seconds"," is optional; when omitted, the agent uses the timeout served with the lease.",[10,97,98],{},"The command template supports four variables:",[100,101,102,115],"table",{},[103,104,105],"thead",{},[106,107,108,112],"tr",{},[109,110,111],"th",{},"Variable",[109,113,114],{},"Value",[116,117,118,129,139,149],"tbody",{},[106,119,120,126],{},[121,122,123],"td",{},[32,124,125],{},"{prompt_path}",[121,127,128],{},"Private temporary file containing the rendered slice prompt",[106,130,131,136],{},[121,132,133],{},[32,134,135],{},"{target_path}",[121,137,138],{},"Repository checkout root",[106,140,141,146],{},[121,142,143],{},[32,144,145],{},"{model_code}",[121,147,148],{},"Claimed server model code",[106,150,151,156],{},[121,152,153],{},[32,154,155],{},"{slice_id}",[121,157,158],{},"Claimed slice identifier",[10,160,161],{},"The agent shell-quotes substituted values. Unknown variables fail before the process starts.",[14,163,165],{"id":164},"follow-the-stdout-contract","Follow the stdout contract",[10,167,168],{},"The command may write progress or diagnostics before and after the result block. It must write one JSON array between the opening and closing marker from the prompt:",[52,170,175],{"className":171,"code":173,"language":174,"meta":57},[172],"language-text","model progress can appear here\n\u003CTHESPIDER_FINDINGS_JSON>\n[\n  {\n    \"title\": \"Authorization missing on project update\",\n    \"severity\": \"high\",\n    \"confidence\": 0.94,\n    \"categories\": [\"authz\"],\n    \"files\": [{ \"path\": \"src\u002Fhttp\u002Fprojects.ts\", \"line\": 88 }],\n    \"evidence\": \"The update query uses the path id without an organization predicate.\",\n    \"impact\": \"A tenant member can modify another tenant's project.\",\n    \"recommendation\": \"Apply tenant scope before the update.\"\n  }\n]\n\u003C\u002FTHESPIDER_FINDINGS_JSON>\n","text",[32,176,173],{"__ignoreMap":57},[10,178,179],{},"Write process diagnostics to stderr. The agent uploads only the final 4,000 characters of stderr.",[10,181,182,183,188],{},"Read the canonical ",[184,185,187],"a",{"href":186},"\u002Fdocs\u002Freference\u002Frunner-contract","runner contract"," for marker parsing, exit handling, size limits, and submission dispositions.",[14,190,192],{"id":191},"configure-opencode","Configure OpenCode",[10,194,195,196,199,200,203],{},"The repository ships ",[32,197,198],{},"runners\u002Fopencode-runner.sh",". It creates a fresh OpenCode session with ",[32,201,202],{},"occtl",", sends the prompt, waits for a complete marker-delimited JSON array, and prints the assistant's final text to stdout.",[52,205,207],{"className":54,"code":206,"language":56,"meta":57,"style":57},"[[model]]\ncode = \"opencode-sonnet\"\ncommand = \"\u002Fopt\u002Fthespider\u002Frunners\u002Fopencode-runner.sh {prompt_path} anthropic\u002Fclaude-sonnet-4-6\"\ntimeout_seconds = 3600\n",[32,208,209,213,218,223],{"__ignoreMap":57},[61,210,211],{"class":63,"line":64},[61,212,67],{},[61,214,215],{"class":63,"line":70},[61,216,217],{},"code = \"opencode-sonnet\"\n",[61,219,220],{"class":63,"line":76},[61,221,222],{},"command = \"\u002Fopt\u002Fthespider\u002Frunners\u002Fopencode-runner.sh {prompt_path} anthropic\u002Fclaude-sonnet-4-6\"\n",[61,224,225],{"class":63,"line":82},[61,226,227],{},"timeout_seconds = 3600\n",[10,229,230],{},"Requirements:",[19,232,233,242,257],{},[22,234,235,237,238,241],{},[32,236,202],{}," 1.1.0 or newer is on ",[32,239,240],{},"PATH",".",[22,243,244,245,248,249,252,253,256],{},"An OpenCode server is reachable at ",[32,246,247],{},"127.0.0.1:4096",", or ",[32,250,251],{},"OPENCODE_SERVER_HOST"," and ",[32,254,255],{},"OPENCODE_SERVER_PORT"," point to it.",[22,258,259,262],{},[32,260,261],{},"OPENCODE_CAPTURE_TIMEOUT"," is shorter than the model binding timeout.",[10,264,265,266,269,270,273],{},"The runner keeps a failed or empty OpenCode session and writes its identifier beside the prompt as ",[32,267,268],{},"session.id",". Recover it with the command printed to stderr. Set ",[32,271,272],{},"OPENCODE_KEEP_SESSION=1"," to retain successful sessions too.",[14,275,277],{"id":276},"smoke-test-without-a-model-provider","Smoke-test without a model provider",[10,279,280],{},"The repository's deterministic fake model reads the prompt path and emits a marker-compliant security or bug report without external calls:",[52,282,284],{"className":54,"code":283,"language":56,"meta":57,"style":57},"[[model]]\ncode = \"fake\"\ncommand = \"bun \u002Fopt\u002Fthespider\u002Ffake-model.ts {prompt_path}\"\ntimeout_seconds = 60\n",[32,285,286,290,295,300],{"__ignoreMap":57},[61,287,288],{"class":63,"line":64},[61,289,67],{},[61,291,292],{"class":63,"line":70},[61,293,294],{},"code = \"fake\"\n",[61,296,297],{"class":63,"line":76},[61,298,299],{},"command = \"bun \u002Fopt\u002Fthespider\u002Ffake-model.ts {prompt_path}\"\n",[61,301,302],{"class":63,"line":82},[61,303,304],{},"timeout_seconds = 60\n",[10,306,307],{},"Run a single batch:",[52,309,313],{"className":310,"code":311,"language":312,"meta":57,"style":57},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","thespider-agent run --once --models fake\n","bash",[32,314,315],{"__ignoreMap":57},[61,316,317,321,325,328,331],{"class":63,"line":64},[61,318,320],{"class":319},"sBMFI","thespider-agent",[61,322,324],{"class":323},"sfazB"," run",[61,326,327],{"class":323}," --once",[61,329,330],{"class":323}," --models",[61,332,333],{"class":323}," fake\n",[10,335,336,337,340,341,345],{},"The command exits with ",[32,338,339],{},"0"," when every submitted slice was accepted or superseded. Open ",[342,343,344],"strong",{},"Slices"," to inspect status, imported report count, duration, and any runner or import error.",[14,347,349],{"id":348},"verify-a-production-binding","Verify a production binding",[351,352,353,356,359,364,370],"ol",{},[22,354,355],{},"Run the command manually against a saved prompt.",[22,357,358],{},"Confirm stdout contains both marker tags and a JSON array immediately after the opening tag.",[22,360,361,362,241],{},"Confirm the process exits before ",[32,363,94],{},[22,365,366,367,241],{},"Run ",[32,368,369],{},"thespider-agent run --once --models MODEL_CODE",[22,371,372,373,376],{},"Confirm the slice reports ",[32,374,375],{},"accepted"," and a nonzero report count.",[378,379,380],"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);}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}",{"title":57,"searchDepth":70,"depth":70,"links":382},[383,384,385,386,387,388],{"id":16,"depth":70,"text":17},{"id":38,"depth":70,"text":39},{"id":164,"depth":70,"text":165},{"id":191,"depth":70,"text":192},{"id":276,"depth":70,"text":277},{"id":348,"depth":70,"text":349},"Bind a local model command to TheSpider's prompt and result contract","md",null,{},{"icon":394},"i-lucide-terminal-square","\u002Fdocs\u002Fguide\u002Fcustom-runner",{"title":5,"description":389},"docs\u002F2.guide\u002F8.custom-runner","nYY1YtduwE5lySIcLz6Mguj718uBkUahvQFTNJ9sGtM",[400,406],{"title":401,"path":402,"stem":403,"description":404,"icon":405,"children":-1},"How to author an audit methodology","\u002Fdocs\u002Fguide\u002Fmethodology","docs\u002F2.guide\u002F7.methodology","Define buckets, categories, passes, scopes, and prompt sections for a project","i-lucide-panels-top-left",{"title":407,"path":408,"stem":409,"description":410,"icon":411,"children":-1},"Runner troubleshooting","\u002Fdocs\u002Fguide\u002Ftroubleshooting","docs\u002F2.guide\u002F9.troubleshooting","Diagnose claim, execution, result import, lease, and daemon failures","i-lucide-wrench",1784724165141]