[{"data":1,"prerenderedAt":332},["ShallowReactive",2],{"-docs-guide-pr-gate":3,"-docs-guide-pr-gate-surround":320},{"id":4,"title":5,"body":6,"description":310,"extension":311,"links":312,"meta":313,"navigation":314,"path":316,"seo":317,"stem":318,"__hash__":319},"docs\u002Fdocs\u002F2.guide\u002F5.pr-gate.md","PR gate",{"type":7,"value":8,"toc":302},"minimark",[9,22,27,38,42,57,82,86,89,121,138,145,149,152,188,208,212,278,282,298],[10,11,12,13,17,18,21],"p",{},"Local model execution conflicts with ephemeral CI: every CI job would need model credentials, a warm checkout, and minutes-per-slice runtimes. TheSpider's first-class team pattern is a ",[14,15,16],"strong",{},"persistent runner daemon"," plus a ",[14,19,20],{},"cheap gate poll"," — CI does no model work at all.",[23,24,26],"h2",{"id":25},"architecture","Architecture",[28,29,35],"pre",{"className":30,"code":32,"language":33,"meta":34},[31],"language-text","  forge webhook ──▶ server (creates incremental campaign, changed_paths from forge API)\n                         ▲\n                         │ polls claimable campaigns\n  thespider-agent daemon (team box \u002F self-hosted runner)\n   • holds project-scoped token + model creds\n   • managed clone: fetch + checkout exact commit\n   • claim → run models locally → submit\n                         │\n  CI job ──GET \u002Fv1\u002Fcampaigns\u002F{id}\u002Fgate──▶ server\n   • exit 0 pass \u002F 1 fail \u002F 2 pending\n   • NO secrets, NO model runtime in CI\n","text","",[36,37,32],"code",{"__ignoreMap":34},[23,39,41],{"id":40},"enable-the-forge-webhook","Enable the forge webhook",[10,43,44,45,48,49,52,53,56],{},"Set ",[36,46,47],{},"GITHUB_WEBHOOK_SECRET"," on the server to enable ",[36,50,51],{},"POST \u002Fv1\u002Fwebhooks\u002Fgithub",". On a ",[36,54,55],{},"pull_request"," opened\u002Fsynchronized event, the server:",[58,59,60,68,75],"ol",{},[61,62,63,64,67],"li",{},"Maps the PR's ",[36,65,66],{},"repo_remote_url"," to a project.",[61,69,70,71,74],{},"Fetches ",[14,72,73],{},"changed paths"," from the forge API (paths only — consistent with the data boundary).",[61,76,77,78,81],{},"Creates an ",[14,79,80],{},"incremental campaign"," scoped by pass-scope globs + risk triggers.",[23,83,85],{"id":84},"run-the-daemon","Run the daemon",[10,87,88],{},"On a team box or self-hosted CI runner:",[28,90,94],{"className":91,"code":92,"language":93,"meta":34,"style":34},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","thespider-agent daemon --workdir \u002Fvar\u002Flib\u002Fthespider --models sonnet\n","bash",[36,95,96],{"__ignoreMap":34},[97,98,101,105,109,112,115,118],"span",{"class":99,"line":100},"line",1,[97,102,104],{"class":103},"sBMFI","thespider-agent",[97,106,108],{"class":107},"sfazB"," daemon",[97,110,111],{"class":107}," --workdir",[97,113,114],{"class":107}," \u002Fvar\u002Flib\u002Fthespider",[97,116,117],{"class":107}," --models",[97,119,120],{"class":107}," sonnet\n",[10,122,123,124,127,128,131,132,137],{},"The daemon polls ",[36,125,126],{},"GET \u002Fv1\u002Fprojects\u002F{id}\u002Fcampaigns\u002Fclaimable",", does a ",[14,129,130],{},"managed clone"," of the campaign's exact commit into a stable per-repo directory, then claims\u002Fruns\u002Fsubmits. See ",[133,134,136],"a",{"href":135},"\u002Fdocs\u002Fguide\u002Fagent#run-the-persistent-daemon-pr-ci-pattern","The agent"," for the full loop, robustness, and git-auth notes.",[139,140,141,142,144],"tip",{},"Set the project's ",[36,143,66],{}," to a URL the runner can actually clone (SSH with a loaded ssh-agent, or HTTPS with an embedded token \u002F credential helper).",[23,146,148],{"id":147},"poll-the-gate-from-ci","Poll the gate from CI",[10,150,151],{},"CI itself only calls one cheap endpoint:",[28,153,155],{"className":91,"code":154,"language":93,"meta":34,"style":34},"thespider-agent gate --campaign \u003Cid>\n# exit 0 = pass, 1 = fail (new findings), 2 = pending\n",[36,156,157,181],{"__ignoreMap":34},[97,158,159,161,164,167,171,174,178],{"class":99,"line":100},[97,160,104],{"class":103},[97,162,163],{"class":107}," gate",[97,165,166],{"class":107}," --campaign",[97,168,170],{"class":169},"sMK4o"," \u003C",[97,172,173],{"class":107},"i",[97,175,177],{"class":176},"sTEyZ","d",[97,179,180],{"class":169},">\n",[97,182,184],{"class":99,"line":183},2,[97,185,187],{"class":186},"sHwdD","# exit 0 = pass, 1 = fail (new findings), 2 = pending\n",[10,189,190,191,194,195,198,199,207],{},"Under the hood that is ",[36,192,193],{},"GET \u002Fv1\u002Fcampaigns\u002F{id}\u002Fgate"," → ",[36,196,197],{},"{ status: pass|fail|pending, new_findings:[...] }",". No model credentials, no long runtimes in CI — see ",[133,200,204],{"href":201,"rel":202},"https:\u002F\u002Fgitlab.com\u002Fdragonstone-labs\u002Fthespider-saas\u002F-\u002Fblob\u002Fmain\u002Fdeploy\u002Fci-gate-example.md",[203],"nofollow",[36,205,206],{},"deploy\u002Fci-gate-example.md"," for a drop-in workflow.",[23,209,211],{"id":210},"interpret-gate-results","Interpret gate results",[213,214,215,231],"table",{},[216,217,218],"thead",{},[219,220,221,225,228],"tr",{},[222,223,224],"th",{},"Exit",[222,226,227],{},"Meaning",[222,229,230],{},"CI action",[232,233,234,248,265],"tbody",{},[219,235,236,242,245],{},[237,238,239],"td",{},[36,240,241],{},"0",[237,243,244],{},"pass — no new findings on the PR",[237,246,247],{},"allow merge",[219,249,250,255,262],{},[237,251,252],{},[36,253,254],{},"1",[237,256,257,258,261],{},"fail — new findings whose earliest sighting is the PR branch (and intersect ",[36,259,260],{},"changed_paths",")",[237,263,264],{},"block \u002F require triage",[219,266,267,272,275],{},[237,268,269],{},[36,270,271],{},"2",[237,273,274],{},"pending — the daemon hasn't finished yet",[237,276,277],{},"wait and re-poll",[23,279,281],{"id":280},"next-steps","Next steps",[283,284,285,291],"ul",{},[61,286,287,290],{},[133,288,136],{"href":289},"\u002Fdocs\u002Fguide\u002Fagent"," — every daemon flag.",[61,292,293,297],{},[133,294,296],{"href":295},"\u002Fdocs\u002Fguide\u002Fdata-handling","Data handling"," — what the webhook and daemon transmit.",[299,300,301],"style",{},"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}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 .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":34,"searchDepth":183,"depth":183,"links":303},[304,305,306,307,308,309],{"id":25,"depth":183,"text":26},{"id":40,"depth":183,"text":41},{"id":84,"depth":183,"text":85},{"id":147,"depth":183,"text":148},{"id":210,"depth":183,"text":211},{"id":280,"depth":183,"text":281},"Gate pull requests without putting model runtime or secrets into CI","md",null,{},{"icon":315},"i-lucide-git-pull-request","\u002Fdocs\u002Fguide\u002Fpr-gate",{"title":5,"description":310},"docs\u002F2.guide\u002F5.pr-gate","fj2EjrlrZHlv4gPV6twQzfkHZmyKKNgjwgjfIqj6xMs",[321,327],{"title":322,"path":323,"stem":324,"description":325,"icon":326,"children":-1},"Triage","\u002Fdocs\u002Fguide\u002Ftriage","docs\u002F2.guide\u002F4.triage","Triage findings as a team with project-level identity and branch attribution","i-lucide-list-checks",{"title":328,"path":295,"stem":329,"description":330,"icon":331,"children":-1},"Data handling & privacy","docs\u002F2.guide\u002F6.data-handling","Exactly what crosses the machine boundary and how secrets are protected","i-lucide-shield-check",1783955419762]