[{"data":1,"prerenderedAt":444},["ShallowReactive",2],{"-docs-guide-agent":3,"-docs-guide-agent-surround":433},{"id":4,"title":5,"body":6,"description":423,"extension":424,"links":425,"meta":426,"navigation":427,"path":429,"seo":430,"stem":431,"__hash__":432},"docs\u002Fdocs\u002F2.guide\u002F2.agent.md","The agent",{"type":7,"value":8,"toc":412},"minimark",[9,26,31,41,45,75,79,85,88,174,178,193,215,218,222,228,235,238,288,292,342,346,355,385,391,395],[10,11,12,16,17,21,22,25],"p",{},[13,14,15],"code",{},"thespider-agent"," is TheSpider's ",[18,19,20],"strong",{},"thin execution agent"," — a single Rust binary. It holds only a server URL, an auth token, and ",[13,23,24],{},"model_code → command"," bindings. All brain logic and all state live server-side; what reaches the client is one rendered prompt per claimed slice, by design.",[27,28,30],"h2",{"id":29},"use-the-command-surface","Use the command surface",[32,33,38],"pre",{"className":34,"code":36,"language":37},[35],"language-text","thespider-agent login          # open \u003Cserver>\u002Factivate, paste enrollment code (stdin), store token\nthespider-agent logout         # clear the stored token (keychain + file)\nthespider-agent status         # org\u002Fprojects\u002Fentitlements, config sanity, token source\nthespider-agent models         # server catalog vs local [[model]] bindings, as a diff\nthespider-agent run [flags]    # claim slices, run models locally, upload results\nthespider-agent gate --campaign \u003Cid>   # poll the PR gate; exit 0 pass \u002F 1 fail \u002F 2 pending\nthespider-agent daemon [flags] # persistent runner: poll → managed-clone → claim\u002Frun\u002Fsubmit\n","text",[13,39,36],{"__ignoreMap":40},"",[27,42,44],{"id":43},"enroll-with-login","Enroll with login",[10,46,47,50,51,54,55,58,59,62,63,66,67,70,71,74],{},[13,48,49],{},"login"," prints (and best-effort opens) ",[13,52,53],{},"\u003Cserver>\u002Factivate",", reads a short ",[18,56,57],{},"enrollment code"," from stdin, and ",[13,60,61],{},"POST","s ",[13,64,65],{},"\u002Fv1\u002Fenroll",". It is identical in SaaS and on-prem — the ",[13,68,69],{},"\u002Factivate"," page is server-side, and enrollment codes are minted in the web UI or via ",[13,72,73],{},"bun run src\u002Fmint-enrollment-code.ts",".",[27,76,78],{"id":77},"run-a-campaign","Run a campaign",[32,80,83],{"className":81,"code":82,"language":37},[35],"thespider-agent run [--campaign \u003Cid>] [--once] [--models a,b] [--target-path \u003Cdir>] [--redact]\n",[13,84,82],{"__ignoreMap":40},[10,86,87],{},"The loop:",[89,90,91,98,113,134,164],"ol",{},[92,93,94,97],"li",{},[13,95,96],{},"GET \u002Fv1\u002Fme"," → resolve org\u002Fproject\u002Fentitlements.",[92,99,100,101,104,105,112],{},"Campaign: ",[13,102,103],{},"--campaign \u003Cid>",", else ",[18,106,107,108,111],{},"create a ",[13,109,110],{},"full"," campaign"," from local git detect (branch\u002Fcommit\u002Fremote_url\u002Fdirty; the client detects, the server records).",[92,114,115,116,119,120,123,124,127,128,130,131,74],{},"Claim a batch (sized to ",[13,117,118],{},"concurrency","), respecting the lease\u002Ftimeout policy. For each lease: write the prompt to a temp file, substitute the model command, spawn ",[13,121,122],{},"sh -c",", capture stdout\u002Fstderr\u002Fexit\u002Fduration, ",[18,125,126],{},"heartbeat the lease"," while the model runs, then ",[13,129,61],{}," the raw stdout echoing ",[13,132,133],{},"prompt_hash",[92,135,136,137,140,141,144,145,148,149,152,153,156,157,160,161,74],{},"Response handling: accepted (",[13,138,139],{},"200","), accepted-as-artifact \u002F superseded (",[13,142,143],{},"202","), prompt_hash mismatch (",[13,146,147],{},"409","), too large (",[13,150,151],{},"413","). Network errors, ",[13,154,155],{},"429",", and ",[13,158,159],{},"5xx"," retry with ",[18,162,163],{},"exponential backoff + jitter",[92,165,166,169,170,173],{},[13,167,168],{},"--once"," processes a single claim batch and stops (CI \u002F one-shot). Without it, ",[13,171,172],{},"run"," loops until no claimable slices remain.",[27,175,177],{"id":176},"redact-on-the-client-opt-in","Redact on the client (opt-in)",[10,179,180,181,184,185,188,189,192],{},"The ",[18,182,183],{},"server"," secret scrubber is always on. ",[13,186,187],{},"--redact"," additionally, on the client, ",[18,190,191],{},"before upload",":",[89,194,195,209],{},[92,196,197,200,201,204,205,208],{},[18,198,199],{},"Masks secret-shaped substrings"," in raw stdout using the same pattern family — PEM private-key blocks, JWTs, ",[13,202,203],{},"Authorization: Bearer"," tokens, AWS access-key ids, GitHub\u002FSlack\u002FGoogle\u002FOpenAI keys, and long high-entropy base64\u002Fhex runs — replacing them with ",[13,206,207],{},"«redacted»",". Ordinary prose, short identifiers, and file paths are preserved.",[92,210,211,214],{},[18,212,213],{},"Truncates"," stdout to at most 1 MiB (stricter than the server's default artifact cap), appending a visible marker.",[10,216,217],{},"It never parses or reshapes findings semantics — it operates purely on the raw stdout string.",[27,219,221],{"id":220},"run-the-persistent-daemon-prci-pattern","Run the persistent daemon (PR\u002FCI pattern)",[32,223,226],{"className":224,"code":225,"language":37},[35],"thespider-agent daemon [--interval \u003Csecs>] [--workdir \u003Cdir>] [--models a,b] [--redact] [--max-iterations \u003Cn>]\n",[13,227,225],{"__ignoreMap":40},[10,229,230,231,234],{},"Run the daemon ",[18,232,233],{},"once"," on a team box or self-hosted CI runner holding a project-scoped token and local model creds; CI jobs then only poll the gate — no model credentials or model runtime in CI.",[10,236,237],{},"Loop:",[89,239,240,245,258,281],{},[92,241,242,244],{},[13,243,96],{}," → resolve the project.",[92,246,247,248,251,252,255,256,74],{},"Poll ",[13,249,250],{},"GET \u002Fv1\u002Fprojects\u002F{id}\u002Fcampaigns\u002Fclaimable"," — campaigns with pending \u002F expired-lease slices, newest first. These are created by the ",[18,253,254],{},"GitHub webhook"," (PR opened\u002Fsynchronized → incremental campaign) or by a developer's ",[13,257,172],{},[92,259,260,261,264,265,268,269,273,274,276,277,280],{},"For each workable campaign: ",[18,262,263],{},"managed clone"," — fetch and check out the campaign's exact commit into ",[13,266,267],{},"\u003Cworkdir>\u002F\u003Cproject>\u002F\u003Cremote-hash>"," (a stable per-repo directory, reused across polls), ",[270,271,272],"em",{},"detached"," — then claim\u002Frun\u002Fsubmit its slices exactly like ",[13,275,172],{},", with ",[13,278,279],{},"{target_path}"," = the managed checkout.",[92,282,283,284,287],{},"Sleep a ",[18,285,286],{},"jittered"," interval (which backs off while idle) and poll again.",[27,289,291],{"id":290},"handle-daemon-robustness","Handle daemon robustness",[293,294,295,309,315,329,335],"ul",{},[92,296,297,300,301,304,305,308],{},[18,298,299],{},"Graceful shutdown"," on ",[13,302,303],{},"SIGINT","\u002F",[13,306,307],{},"SIGTERM"," — the in-flight campaign finishes; no new slices are claimed.",[92,310,311,314],{},[18,312,313],{},"Per-campaign error isolation"," — a bad clone\u002Fcheckout\u002Frun logs and the loop continues.",[92,316,317,318,304,321,324,325,328],{},"A campaign with no ",[13,319,320],{},"remote_url",[13,322,323],{},"commit"," (e.g. a CLI dirty-tree campaign) is ",[18,326,327],{},"skipped",", not errored.",[92,330,331,334],{},[13,332,333],{},"--max-iterations \u003Cn>"," bounds the loop (E2E \u002F one-shot CI).",[92,336,337,338,341],{},"The daemon prints a ",[13,339,340],{},"daemon summary: iterations=… campaigns_worked=… leases=… accepted=… reports=… failed=…"," line.",[27,343,345],{"id":344},"authenticate-the-managed-clone","Authenticate the managed clone",[10,347,348,349,304,352,192],{},"Git auth is git's own — the daemon shells out to ",[13,350,351],{},"git clone",[13,353,354],{},"git fetch",[293,356,357,375],{},[92,358,359,362,363,366,367,370,371,374],{},[18,360,361],{},"SSH remotes"," (",[13,364,365],{},"git@github.com:owner\u002Frepo.git",") → a loaded ",[18,368,369],{},"ssh-agent"," key (or ",[13,372,373],{},"~\u002F.ssh\u002Fconfig"," identity) the daemon's user can use non-interactively.",[92,376,377,380,381,384],{},[18,378,379],{},"HTTPS remotes"," → a token embedded in the remote URL (",[13,382,383],{},"https:\u002F\u002Fx-access-token:\u003CTOKEN>@github.com\u002Fowner\u002Frepo.git",") or a configured git credential helper.",[10,386,180,387,390],{},[13,388,389],{},"repo_remote_url"," a project stores is what the webhook maps PRs to and what the daemon fetches — set it to a URL the runner can actually clone.",[27,392,394],{"id":393},"next-steps","Next steps",[293,396,397,405],{},[92,398,399,404],{},[400,401,403],"a",{"href":402},"\u002Fdocs\u002Fguide\u002Fpr-gate","PR gate"," — wire the webhook and poll from CI.",[92,406,407,411],{},[400,408,410],{"href":409},"\u002Fdocs\u002Fguide\u002Fcampaigns","Campaigns"," — full \u002F incremental \u002F retest semantics.",{"title":40,"searchDepth":413,"depth":413,"links":414},2,[415,416,417,418,419,420,421,422],{"id":29,"depth":413,"text":30},{"id":43,"depth":413,"text":44},{"id":77,"depth":413,"text":78},{"id":176,"depth":413,"text":177},{"id":220,"depth":413,"text":221},{"id":290,"depth":413,"text":291},{"id":344,"depth":413,"text":345},{"id":393,"depth":413,"text":394},"Run the TheSpider Rust agent to claim slices, run models, and gate PRs","md",null,{},{"icon":428},"i-lucide-terminal","\u002Fdocs\u002Fguide\u002Fagent",{"title":5,"description":423},"docs\u002F2.guide\u002F2.agent","IA4VdcWTy-hrmtxfYdlD9R_dvmJ8qz7UwzpNfcUCyzk",[434,440],{"title":435,"path":436,"stem":437,"description":438,"icon":439,"children":-1},"Configuration","\u002Fdocs\u002Fguide\u002Fconfiguration","docs\u002F2.guide\u002F1.configuration","Configure the TheSpider agent and its model command bindings","i-lucide-settings",{"title":410,"path":409,"stem":441,"description":442,"icon":443,"children":-1},"docs\u002F2.guide\u002F3.campaigns","Create and run full, incremental, and retest campaigns in TheSpider","i-lucide-layers",1783955419945]