[{"data":1,"prerenderedAt":698},["ShallowReactive",2],{"navigation_docs":3,"-guide-architecture-overview":168,"-guide-architecture-overview-surround":694},[4,146],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":36},"Guide","i-lucide-book-open","\u002Fguide","1.guide",[10,14,37,55,59,63,67,71,75,79,83,87,109,134,138,142],{"title":11,"path":12,"stem":13},"What is Agent Zero?","\u002Fguide\u002Fintroduction","1.guide\u002F1.introduction",{"title":15,"icon":16,"path":17,"stem":18,"children":19,"page":36},"API","i-lucide-plug","\u002Fguide\u002Fapi","1.guide\u002F10.api",[20,24,28,32],{"title":21,"path":22,"stem":23},"API overview","\u002Fguide\u002Fapi\u002Foverview","1.guide\u002F10.api\u002F1.overview",{"title":25,"path":26,"stem":27},"Define endpoints","\u002Fguide\u002Fapi\u002Fdefine-endpoints","1.guide\u002F10.api\u002F2.define-endpoints",{"title":29,"path":30,"stem":31},"Use the API from a client","\u002Fguide\u002Fapi\u002Fuse-from-client","1.guide\u002F10.api\u002F3.use-from-client",{"title":33,"path":34,"stem":35},"Protect endpoints","\u002Fguide\u002Fapi\u002Fprotect-endpoints","1.guide\u002F10.api\u002F4.protect-endpoints",false,{"title":38,"icon":39,"path":40,"stem":41,"children":42,"page":36},"Authentication","i-lucide-lock","\u002Fguide\u002Fauthentication","1.guide\u002F11.authentication",[43,47,51],{"title":44,"path":45,"stem":46},"Authentication overview","\u002Fguide\u002Fauthentication\u002Foverview","1.guide\u002F11.authentication\u002F1.overview",{"title":48,"path":49,"stem":50},"GitHub OAuth","\u002Fguide\u002Fauthentication\u002Foauth","1.guide\u002F11.authentication\u002F2.oauth",{"title":52,"path":53,"stem":54},"Permissions","\u002Fguide\u002Fauthentication\u002Fpermissions","1.guide\u002F11.authentication\u002F3.permissions",{"title":56,"path":57,"stem":58},"Organizations","\u002Fguide\u002Forganizations","1.guide\u002F12.organizations",{"title":60,"path":61,"stem":62},"Frontend","\u002Fguide\u002Ffrontend","1.guide\u002F13.frontend",{"title":64,"path":65,"stem":66},"Mails","\u002Fguide\u002Fmails","1.guide\u002F14.mails",{"title":68,"path":69,"stem":70},"Internationalization","\u002Fguide\u002Finternationalization","1.guide\u002F15.internationalization",{"title":72,"path":73,"stem":74},"Deployment","\u002Fguide\u002Fdeployment","1.guide\u002F16.deployment",{"title":76,"path":77,"stem":78},"Tech stack","\u002Fguide\u002Ftech-stack","1.guide\u002F2.tech-stack",{"title":80,"path":81,"stem":82},"Installation","\u002Fguide\u002Finstallation","1.guide\u002F3.installation",{"title":84,"path":85,"stem":86},"Environment variables","\u002Fguide\u002Fenvironment-variables","1.guide\u002F4.environment-variables",{"title":88,"icon":89,"path":90,"stem":91,"children":92,"page":36},"Codebase","i-lucide-folder-tree","\u002Fguide\u002Fcodebase","1.guide\u002F5.codebase",[93,97,101,105],{"title":94,"path":95,"stem":96},"Codebase structure","\u002Fguide\u002Fcodebase\u002Fstructure","1.guide\u002F5.codebase\u002F1.structure",{"title":98,"path":99,"stem":100},"Dependencies","\u002Fguide\u002Fcodebase\u002Fdependencies","1.guide\u002F5.codebase\u002F2.dependencies",{"title":102,"path":103,"stem":104},"Formatting and linting","\u002Fguide\u002Fcodebase\u002Fformatting-linting","1.guide\u002F5.codebase\u002F3.formatting-linting",{"title":106,"path":107,"stem":108},"Agent Skills","\u002Fguide\u002Fcodebase\u002Fagent-skills","1.guide\u002F5.codebase\u002F4.agent-skills",{"title":110,"icon":111,"path":112,"stem":113,"children":114,"page":36},"Architecture","i-lucide-layers","\u002Fguide\u002Farchitecture","1.guide\u002F6.architecture",[115,118,122,126,130],{"title":110,"path":116,"stem":117},"\u002Fguide\u002Farchitecture\u002Foverview","1.guide\u002F6.architecture\u002F1.overview",{"title":119,"path":120,"stem":121},"State machine","\u002Fguide\u002Farchitecture\u002Fstate-machine","1.guide\u002F6.architecture\u002F2.state-machine",{"title":123,"path":124,"stem":125},"Execution boundary","\u002Fguide\u002Farchitecture\u002Fexecution-boundary","1.guide\u002F6.architecture\u002F3.execution-boundary",{"title":127,"path":128,"stem":129},"Issue-to-PR workflow","\u002Fguide\u002Farchitecture\u002Fissue-to-pr","1.guide\u002F6.architecture\u002F4.issue-to-pr",{"title":131,"path":132,"stem":133},"Adding a capability","\u002Fguide\u002Farchitecture\u002Fadding-a-capability","1.guide\u002F6.architecture\u002F5.adding-a-capability",{"title":135,"path":136,"stem":137},"Repository policy","\u002Fguide\u002Fconfiguration","1.guide\u002F7.configuration",{"title":139,"path":140,"stem":141},"Safety model","\u002Fguide\u002Fsafety","1.guide\u002F8.safety",{"title":143,"path":144,"stem":145},"Database","\u002Fguide\u002Fdatabase","1.guide\u002F9.database",{"title":147,"icon":148,"path":149,"stem":150,"children":151,"page":36},"Reference","i-lucide-book-marked","\u002Freference","2.reference",[152,156,160,164],{"title":153,"path":154,"stem":155},"CLI","\u002Freference\u002Fcli","2.reference\u002F1.cli",{"title":157,"path":158,"stem":159},"Model providers","\u002Freference\u002Fmodel-providers","2.reference\u002F2.model-providers",{"title":161,"path":162,"stem":163},"Source-control providers","\u002Freference\u002Fsource-control-providers","2.reference\u002F3.source-control-providers",{"title":165,"path":166,"stem":167},"Sandbox providers","\u002Freference\u002Fsandbox-providers","2.reference\u002F4.sandbox-providers",{"id":169,"title":110,"body":170,"description":176,"extension":688,"links":689,"meta":690,"navigation":691,"path":116,"seo":692,"stem":117,"__hash__":693},"docs\u002F1.guide\u002F6.architecture\u002F1.overview.md",{"type":171,"value":172,"toc":680},"minimark",[173,177,188,193,290,293,297,338,372,376,381,395,399,407,476,500,533,551,554,558,620,666,677],[174,175,176],"p",{},"Agent Zero is organized as a dependency-directed monorepo. The core decides what should happen; adapters decide how external systems communicate with it; the runner controls what is allowed to happen to a checkout.",[178,179,185],"pre",{"className":180,"code":182,"language":183,"meta":184},[181],"language-text","Source-control adapters ─┐\nCLI adapter ─────────────┼──> agent runtime ──> runner boundary ──> isolated checkout\npackages\u002Fapi ────────────┘        │\n                         ├──> model abstraction ──> provider\n                         └──> shared contracts\n\napps\u002Fdashboard: UI + packages\u002Fapi's router (oRPC + OpenAPI) + Better Auth ──> database package ──> Postgres\nNuxt marketing ───> public site (no inbound dependencies)\n","text","",[186,187,182],"code",{"__ignoreMap":184},[189,190,192],"h2",{"id":191},"dependency-direction","Dependency direction",[194,195,196,203,220,226,232,238,247,256,280],"ul",{},[197,198,199,202],"li",{},[186,200,201],{},"shared"," contains stable data contracts and must not import feature packages.",[197,204,205,208,209,208,212,215,216,219],{},[186,206,207],{},"config",", ",[186,210,211],{},"models",[186,213,214],{},"source-control",", and ",[186,217,218],{},"runner"," implement focused capabilities around shared contracts.",[197,221,222,225],{},[186,223,224],{},"agent"," composes policies and state transitions without knowing HTTP or terminal details.",[197,227,228,231],{},[186,229,230],{},"cli"," is an entry-point adapter. It may depend on the runtime, but the runtime must not depend on it.",[197,233,234,237],{},[186,235,236],{},"database"," owns the schema, the Drizzle client, and the migrations. It is the only package that talks to Postgres, and it holds no policy.",[197,239,240,243,244,246],{},[186,241,242],{},"auth"," holds authentication policy and a Better Auth options factory, and reads the store through ",[186,245,236],{},". It does not depend on the runtime.",[197,248,249,252,253,255],{},[186,250,251],{},"packages\u002Fapi"," composes the runtime, source-control, models, and config adapters into one router. It may depend on all of them; none of them may depend on it. It does not depend on ",[186,254,242],{},".",[197,257,258,261,262,265,266,268,269,272,273,276,277,255],{},[186,259,260],{},"apps\u002Fdashboard"," is the entry-point adapter and composition root: a Nuxt app whose ",[186,263,264],{},"server\u002F"," directory serves ",[186,267,251],{},"'s router and, through its own ",[186,270,271],{},"server\u002Fauth.config.ts"," composing ",[186,274,275],{},"packages\u002Fauth","'s options, is the only process that opens the database, through ",[186,278,279],{},"packages\u002Fdatabase",[197,281,282,285,286,289],{},[186,283,284],{},"apps\u002Fmarketing"," is a frontend-only Nuxt site with no dependents and no dependencies beyond ",[186,287,288],{},"packages\u002Fi18n",". Nothing may import it.",[174,291,292],{},"If a change creates a reverse dependency, move the shared contract inward instead of importing an adapter into the runtime.",[189,294,296],{"id":295},"api-package","API package",[174,298,299,301,302,304,305,208,308,208,311,208,314,208,317,320,321,208,324,208,327,330,331,333,334,337],{},[186,300,251],{}," is the library ",[186,303,260],{},"'s server reads from: it composes the agent runtime, source-control adapter, model abstraction, and config into one typed oRPC router (",[186,306,307],{},"health",[186,309,310],{},"tasks.list",[186,312,313],{},"tasks.get",[186,315,316],{},"tasks.create",[186,318,319],{},"approvals.decide",") and a control-plane operations layer (",[186,322,323],{},"runTask",[186,325,326],{},"TaskScheduler",[186,328,329],{},"TaskStore","). It holds no HTTP host of its own and does not depend on ",[186,332,275],{}," — ",[186,335,336],{},"apps\u002Fdashboard\u002Fserver\u002F"," is the only place that constructs a transport handler from it, which keeps the router and its authorization rules identical regardless of which wire protocol serves a given request.",[174,339,340,341,343,344,347,348,351,352,355,356,359,360,363,364,367,368,371],{},"Procedures validate at the boundary with Zod and then delegate; they never invoke a shell or touch a checkout, because ",[186,342,323],{}," is the only place that resolves policy and constructs a runner. A hosted ",[186,345,346],{},"RunnerPool"," lease is optional and still yields nothing but a ",[186,349,350],{},"Runner",". ",[186,353,354],{},"EvlogHandlerPlugin",", shared by every transport through one ",[186,357,358],{},"AsyncLocalStorage","-backed logger (",[186,361,362],{},"packages\u002Fapi\u002Fsrc\u002Forpc\u002Flogging.ts","), attaches structured request logs; procedures read it defensively (",[186,365,366],{},"requestLoggerStorage?.getStore()?.set(...)",") so router tests that call procedures directly through ",[186,369,370],{},"createRouterClient",", without a transport's plugin attached, still pass.",[189,373,375],{"id":374},"marketing-boundary","Marketing boundary",[174,377,378,380],{},[186,379,284],{}," is the public site and holds the weakest position in the graph: no persistence, no credentials, no session, and no runtime-package imports. It links to the dashboard by origin rather than importing anything from it, so the two deploy and fail independently.",[174,382,383,384,387,388,391,392,394],{},"It differs from the dashboard in exactly one respect. The dashboard renders with SSR because its session cookie is scoped to its own origin, so the server resolves it directly from the incoming request; the marketing site renders on the server too, but for a different reason — being crawlable is the entire point of it, so it prerenders every route rather than depending on a live request. That gives it a Nitro server, but the only routes on it are the ones ",[186,385,386],{},"@nuxtjs\u002Fseo"," generates — ",[186,389,390],{},"robots.txt"," and the sitemaps. Anything that needs to read or write state belongs behind the dashboard's ",[186,393,264],{}," routes, not here.",[189,396,398],{"id":397},"dashboard-and-control-plane-boundary","Dashboard and control-plane boundary",[174,400,401,403,404,406],{},[186,402,260],{}," is the composition root and the only entry-point adapter with HTTP capability: a Nuxt app whose ",[186,405,264],{}," directory hosts",[408,409,410,423],"table",{},[411,412,413],"thead",{},[414,415,416,420],"tr",{},[417,418,419],"th",{},"Route",[417,421,422],{},"Purpose",[424,425,426,439,460],"tbody",{},[414,427,428,434],{},[429,430,431],"td",{},[186,432,433],{},"\u002Frpc\u002F**",[429,435,436,438],{},[186,437,251],{},"'s router over the typed oRPC RPC transport",[414,440,441,446],{},[429,442,443],{},[186,444,445],{},"\u002Fapi\u002Fv1\u002F**",[429,447,448,449,452,453,456,457],{},"The same router over OpenAPI\u002FREST (",[186,450,451],{},"OpenAPIHandler","); docs at ",[186,454,455],{},"\u002Fapi\u002Fv1\u002Fdocs",", spec at ",[186,458,459],{},"\u002Fapi\u002Fv1\u002Fopenapi.json",[414,461,462,467],{},[429,463,464],{},[186,465,466],{},"\u002Fapi\u002Fauth\u002F**",[429,468,469,470,473,474],{},"The Better Auth handler, mounted by ",[186,471,472],{},"@onmax\u002Fnuxt-better-auth"," from ",[186,475,271],{},[174,477,478,480,481,483,484,487,488,491,492,495,496,499],{},[186,479,433],{}," and ",[186,482,445],{}," serve the exact same ",[186,485,486],{},"rpcRouter"," and therefore the exact same authorization rules; only the wire protocol differs. ",[186,489,490],{},".meta(openapi(...))"," metadata on each procedure (method, path, tags) exists purely for the OpenAPI transport and has no effect on the RPC transport — it is attached through a real, regularly-imported function rather than the ",[186,493,494],{},"@orpc\u002Fopenapi"," package's alternative bare side-effect import, because Nitro's production bundler tree-shakes an unused side-effect import away even though the package's own ",[186,497,498],{},"sideEffects"," field marks it as one to keep.",[174,501,502,503,506,507,510,511,513,514,517,518,521,522,525,526,480,529,532],{},"Mutations fail closed behind operator-issued bearer credentials (",[186,504,505],{},"AGENT_ZERO_CONTROL_PLANE_TOKENS",", comma-separated ",[186,508,509],{},"name:token"," pairs). ",[186,512,316],{}," additionally requires the target repository path to appear in ",[186,515,516],{},"AGENT_ZERO_CONTROL_PLANE_REPOSITORIES",", so an HTTP caller cannot point a run at an arbitrary server-local path, and the requested execution mode to be granted to the principal via ",[186,519,520],{},"AGENT_ZERO_CONTROL_PLANE_MODES"," (comma-separated ",[186,523,524],{},"name:mode|mode"," grants; without one a principal is limited to the non-writable ",[186,527,528],{},"observe",[186,530,531],{},"suggest"," modes). Approval decisions record the authenticated principal's name rather than a wire-supplied actor. Reads stay open for the dashboard. This bearer-token scheme is independent of the Better Auth session that protects the dashboard UI itself.",[174,534,535,536,539,540,543,544,547,548,550],{},"Task persistence is a narrow ",[186,537,538],{},"KeyValueStorage"," contract adapted over the ViteHub KV Runtime Helper (",[186,541,542],{},"apps\u002Fdashboard\u002Fnuxt.config.ts"," registers ",[186,545,546],{},"vite-hub\u002Fnuxt",", composing ViteHub into Nuxt's own Nitro build), so the filesystem driver, Cloudflare KV, Deno KV, or Upstash stays interchangeable. Records are redacted on the way in and hold no review input and no checkout path, so task history cannot become a credential or filesystem leak. ",[186,549,326],{}," bounds concurrency globally and per repository, and rejects work once the queue is exhausted rather than growing without limit.",[174,552,553],{},"Transport concerns stop at the route handlers: headers, status mapping, and request objects never reach a runtime package.",[189,555,557],{"id":556},"authentication-boundary","Authentication boundary",[174,559,560,561,563,564,566,567,569,570,572,573,575,576,579,580,583,584,586,587,589,590,593,594,208,597,215,600,603,604,606,607,610,611,613,614,563,616,619],{},"Authentication follows the same adapter rule at the package level, but not at the process level: Better Auth is mounted in-process by ",[186,562,260],{},"'s ",[186,565,466],{}," route (",[186,568,271],{},"), the only route in the app that resolves ",[186,571,275],{},"'s environment options — including the connection string, through ",[186,574,279],{}," — and the signing secret (",[186,577,578],{},"NUXT_BETTER_AUTH_SECRET",", required in production; ",[186,581,582],{},"BETTER_AUTH_SECRET"," only works as a development fallback) and therefore the only part of the app that opens a connection to Postgres, the only database in the repository. Every other route reaches storage exclusively through the ",[186,585,538],{}," contract. ",[186,588,275],{}," holds the policy: ",[186,591,592],{},"authBetterAuthOptions"," builds the database, policy, and provider options Better Auth needs, deliberately omitting ",[186,595,596],{},"secret",[186,598,599],{},"baseURL",[186,601,602],{},"trustedOrigins"," so the ",[186,605,472],{}," module — which resolves those itself and constructs the actual instance — cannot diverge from it. ",[186,608,609],{},"createAuth",", which does build a full standalone instance, remains for callers that own their own secret and origin, such as the Better Auth CLI's schema-generation entry point; nothing in ",[186,612,260],{},"'s request path uses it. ",[186,615,275],{},[186,617,618],{},".\u002Fconfig"," subpath stays free of database dependencies so the login page can read feature flags without bundling one.",[174,621,622,623,626,627,629,630,563,632,634,635,638,639,642,643,646,647,650,651,654,655,658,659,661,662,665],{},"Invitations (",[186,624,625],{},"AUTH_ENABLE_INVITATIONS",") are the Better Enrollment plugin, composed by the same factory and under the same rule: ",[186,628,275],{}," decides policy and declares delivery structurally, and ",[186,631,260],{},[186,633,271],{}," binds ",[186,636,637],{},"packages\u002Fmail"," to it. The plugin's mode is auto-detected from the sign-up policy rather than configured a second time — with ",[186,640,641],{},"AUTH_ENABLE_SIGNUP"," off every sign-up route is closed and invitations are the only way in, and with it on they degrade to role and organization grants — so the two cannot drift apart. Enabling Better Enrollment fails startup without both a mail transport and a dashboard origin: a private invitation's link is deliberately never returned to whoever created it, so email is the only path the token travels, and an undeliverable invitation reaches nobody at all rather than failing loudly. Better Auth's separate organization plugin has no mail-delivery callback in this composition and does not depend on the dashboard origin. A public invitation still returns its shareable link once from create or resend, while Better Enrollment's ",[186,644,645],{},"sendPublicInvitation"," callback also sends the inviter a durable copy when it has an attributable email address; headless system invitations without one keep relying on the returned link. Every Better Enrollment link points at one path, ",[186,648,649],{},"\u002Finvite?token=",", because what the redemption page must render is decided by the auth server when it reads the token; encoding the invitation's kind in the URL would both duplicate that decision and disclose it to anyone the link is forwarded to. That page renders whichever form the server's ",[186,652,653],{},"nextAction"," names and submits only the fields its ",[186,656,657],{},"requiredFields"," asks for, so one page covers private and public invitations, app and organization ones, and both modes. It is the one authenticated-surface route with no ",[186,660,242],{}," route rule: requiring a session would turn away the signed-out invitee it exists for, and requiring a guest would turn away the signed-in one accepting an organization invitation. Redemption deliberately does not start a session, so a newly created account is handed to the sign-in page with the credentials it just set — for a private invitation the page never learns the full address anyway, since ",[186,663,664],{},"invite.get"," returns it masked.",[174,667,668,669,672,673,676],{},"The app-wide ",[186,670,671],{},"user.role"," column belongs to this boundary too, and is distinct from ",[186,674,675],{},"member.role",", which scopes a role to a single organization. Better Auth keeps multiple app-wide roles in one comma-separated string, and only invitation redemption merges into it; any other write replaces the whole set, so code that changes a role has to send the full set or it silently revokes the rest.",[174,678,679],{},"The dashboard renders with SSR. The session cookie is scoped to the app's own origin, so the server resolves it directly from the incoming request before the first paint, rather than rendering a signed-out shell that a client-side check then corrects.",{"title":184,"searchDepth":681,"depth":681,"links":682},2,[683,684,685,686,687],{"id":191,"depth":681,"text":192},{"id":295,"depth":681,"text":296},{"id":374,"depth":681,"text":375},{"id":397,"depth":681,"text":398},{"id":556,"depth":681,"text":557},"md",null,{},true,{"title":110,"description":176},"k4SZR3si3MTB0UZPjI2vxTYaowQ5K0mOG9ZMwJZa1-E",[695,697],{"title":106,"path":107,"stem":108,"description":696,"children":-1},"Task-specific Agent Skills give coding agents (and humans) focused guidance for safety-sensitive or convention-heavy work. They live in .skills\u002F — one directory per skill, each with a SKILL.md — and are exposed to coding agents through .agents\u002Fskills\u002F, managed by skilld.",{"title":119,"path":120,"stem":121,"description":184,"children":-1},1787482154164]