[{"data":1,"prerenderedAt":1194},["ShallowReactive",2],{"navigation_docs":3,"-docs-architecture-repository-content-ingest":158,"-docs-architecture-repository-content-ingest-surround":1189},[4,15,74,98,113],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":6},"Getting Started",false,"\u002Fdocs\u002Fgetting-started","docs\u002F1.getting-started",[10],{"title":11,"path":12,"stem":13,"icon":14},"Zeeq Introduction","\u002Fdocs\u002Fgetting-started\u002Fintroduction","docs\u002F1.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"children":19,"page":6},"Key Features","\u002Fdocs\u002Fkey-features","docs\u002F3.key-features",[20,25,30,35,40,45,50,55,59,64,69],{"title":21,"path":22,"stem":23,"icon":24},"Membership Invitations","\u002Fdocs\u002Fkey-features\u002Fmembership-invitations","docs\u002F3.key-features\u002F1.membership-invitations","i-hugeicons-cube",{"title":26,"path":27,"stem":28,"icon":29},"Command Palette","\u002Fdocs\u002Fkey-features\u002Fcommand-palette","docs\u002F3.key-features\u002F10.command-palette","i-hugeicons-search-01",{"title":31,"path":32,"stem":33,"icon":34},"Library Import and Export","\u002Fdocs\u002Fkey-features\u002Flibrary-import-export","docs\u002F3.key-features\u002F11.library-import-export","i-lucide-package-open",{"title":36,"path":37,"stem":38,"icon":39},"LLM Settings Configuration","\u002Fdocs\u002Fkey-features\u002Fllm-settings-configuration","docs\u002F3.key-features\u002F2.llm-settings-configuration","i-hugeicons-ai-magic",{"title":41,"path":42,"stem":43,"icon":44},"Agent Code Review Findings","\u002Fdocs\u002Fkey-features\u002Fagent-code-review-findings","docs\u002F3.key-features\u002F3.agent-code-review-findings","i-lucide-list-checks",{"title":46,"path":47,"stem":48,"icon":49},"Credentials & API Tokens","\u002Fdocs\u002Fkey-features\u002Fcredentials","docs\u002F3.key-features\u002F4.credentials","i-hugeicons-key-01",{"title":51,"path":52,"stem":53,"icon":54},"Manual Document Libraries","\u002Fdocs\u002Fkey-features\u002Fmanual-document-libraries","docs\u002F3.key-features\u002F5.manual-document-libraries","i-lucide-library-big",{"title":56,"path":57,"stem":58,"icon":29},"Snippet Search","\u002Fdocs\u002Fkey-features\u002Fsnippet-search","docs\u002F3.key-features\u002F6.snippet-search",{"title":60,"path":61,"stem":62,"icon":63},"Shared Prompt Fragment","\u002Fdocs\u002Fkey-features\u002Fshared-prompt-fragment","docs\u002F3.key-features\u002F7.shared-prompt-fragment","i-lucide-notebook-pen",{"title":65,"path":66,"stem":67,"icon":68},"Code Review Sources & Telemetry","\u002Fdocs\u002Fkey-features\u002Fcode-review-sources","docs\u002F3.key-features\u002F8.code-review-sources","i-hugeicons-book-01",{"title":70,"path":71,"stem":72,"icon":73},"Excluding Documents from Code Reviews","\u002Fdocs\u002Fkey-features\u002Fcode-review-document-exclusion","docs\u002F3.key-features\u002F9.code-review-document-exclusion","i-lucide-eye-off",{"title":75,"path":76,"stem":77,"children":78,"page":6},"Runtime Configuration","\u002Fdocs\u002Fconfiguration","docs\u002F5.configuration",[79,84,89,93],{"title":80,"path":81,"stem":82,"icon":83},"Google Cloud Configuration","\u002Fdocs\u002Fconfiguration\u002Fgcp-runtime","docs\u002F5.configuration\u002F1.gcp-runtime","i-hugeicons-google",{"title":85,"path":86,"stem":87,"icon":88},"GitHub Configuration","\u002Fdocs\u002Fconfiguration\u002Fgithub-configuration","docs\u002F5.configuration\u002F2.github-configuration","i-hugeicons-github",{"title":90,"path":91,"stem":92},"Local OpenIddict Certificates","\u002Fdocs\u002Fconfiguration\u002Flocal-openiddict-certificates","docs\u002F5.configuration\u002F3.local-openiddict-certificates",{"title":94,"path":95,"stem":96,"icon":97},"System Admin Access","\u002Fdocs\u002Fconfiguration\u002Fsystem-admin-access","docs\u002F5.configuration\u002F4.system-admin-access","i-hugeicons-shield-01",{"title":99,"path":100,"stem":101,"children":102,"page":6},"Metrics","\u002Fdocs\u002Fmetrics","docs\u002F6.metrics",[103,108],{"title":104,"path":105,"stem":106,"icon":107},"Metrics Dashboard","\u002Fdocs\u002Fmetrics\u002Fmetrics-dashboard","docs\u002F6.metrics\u002F1.metrics-dashboard","i-hugeicons-analytics-01",{"title":109,"path":110,"stem":111,"icon":112},"Metrics Pipeline","\u002Fdocs\u002Fmetrics\u002Fmetrics-pipeline","docs\u002F6.metrics\u002F2.metrics-pipeline","i-hugeicons-database-02",{"title":114,"path":115,"stem":116,"children":117,"page":6},"Design and Architecture","\u002Fdocs\u002Farchitecture","docs\u002F9.architecture",[118,123,128,133,137,141,145,150,154],{"title":119,"path":120,"stem":121,"icon":122},"Caching","\u002Fdocs\u002Farchitecture\u002Fcaching","docs\u002F9.architecture\u002F1.caching","i-lucide-database",{"title":124,"path":125,"stem":126,"icon":127},"Messaging and Queueing","\u002Fdocs\u002Farchitecture\u002Fmessaging-and-queueing","docs\u002F9.architecture\u002F2.messaging-and-queueing","i-lucide-message-square",{"title":129,"path":130,"stem":131,"icon":132},"GitHub Comment Rendering","\u002Fdocs\u002Farchitecture\u002Fgithub-comment-rendering","docs\u002F9.architecture\u002F3.github-comment-rendering","i-lucide-github",{"title":134,"path":135,"stem":136},"GitHub Integration","\u002Fdocs\u002Farchitecture\u002Fgithub-integration","docs\u002F9.architecture\u002F4.github-integration",{"title":138,"path":139,"stem":140},"LLM Settings and Secret Storage","\u002Fdocs\u002Farchitecture\u002Fllm-settings-and-secret-storage","docs\u002F9.architecture\u002F5.llm-settings-and-secret-storage",{"title":142,"path":143,"stem":144},"Organization Activation and Routes","\u002Fdocs\u002Farchitecture\u002Forganization-activation-and-routes","docs\u002F9.architecture\u002F6.organization-activation-and-routes",{"title":146,"path":147,"stem":148,"icon":149},"MCP Uploaded-Diff Code Reviews","\u002Fdocs\u002Farchitecture\u002Fmcp-uploaded-diff-code-reviews","docs\u002F9.architecture\u002F7.mcp-uploaded-diff-code-reviews","i-lucide-file-search",{"title":151,"path":152,"stem":153},"Repository Content Ingest","\u002Fdocs\u002Farchitecture\u002Frepository-content-ingest","docs\u002F9.architecture\u002F8.repository-content-ingest",{"title":155,"path":156,"stem":157},"Telemetry Ingest","\u002Fdocs\u002Farchitecture\u002Ftelemetry-ingest","docs\u002F9.architecture\u002F9.telemetry-ingest",{"id":159,"title":151,"body":160,"description":1181,"extension":1182,"links":1183,"meta":1184,"navigation":1186,"path":152,"seo":1187,"stem":153,"__hash__":1188},"docs\u002Fdocs\u002F9.architecture\u002F8.repository-content-ingest.md",{"type":161,"value":162,"toc":1161},"minimark",[163,168,173,177,194,197,201,212,215,219,327,331,443,451,455,458,487,490,494,497,529,536,553,563,566,571,582,625,645,656,660,663,686,690,752,756,763,855,887,904,908,911,965,971,974,977,984,991,995,1002,1026,1032,1092,1095,1110,1114],[164,165,167],"callout",{"icon":166},"i-lucide-construction","This feature is still in progress. Private-source scheduling, public-source union filters across libraries, and public-source visibility re-verification are not built yet. This page documents what exists today and calls out the known gaps.",[169,170,172],"h2",{"id":171},"summary","Summary",[174,175,176],"p",{},"Repository content ingest clones a GitHub repository, walks its Markdown files, and upserts each one as a document. It runs against two kinds of source:",[178,179,180,188],"ul",{},[181,182,183,187],"li",{},[184,185,186],"strong",{},"Public sources"," — one repository shared across every organization. Documents land in a single global table, and any library can subscribe to a subset of them.",[181,189,190,193],{},[184,191,192],{},"Private sources"," — a repository owned by one organization's library. Documents land in that library's own table, exactly like hand-authored documents.",[174,195,196],{},"Both kinds go through the same pipeline: acquire a workspace (a git clone), walk the files that match the configured filter, parse and hash each one, and upsert it with move detection. The only thing that differs is which database table the documents land in.",[169,198,200],{"id":199},"high-level-flow","High-Level Flow",[202,203,209],"pre",{"className":204,"code":206,"language":207,"meta":208},[205],"language-text","Trigger (manual HTTP call, or the scheduler on a timer)\n  -> publish a \"sync requested\" message\n  -> a message handler picks it up\n  -> the handler asks a dispatcher to run the job\n  -> the dispatcher acquires a workspace (git clone)\n  -> the runner walks the workspace and upserts documents\n  -> the dispatcher disposes the workspace (deletes the clone)\n","text","",[210,211,206],"code",{"__ignoreMap":208},[174,213,214],{},"Every step after \"publish a message\" happens outside the original HTTP request. Triggering a sync returns immediately with a token; the actual clone and upsert work happens on a message queue worker.",[169,216,218],{"id":217},"key-pieces","Key Pieces",[220,221,222,235],"table",{},[223,224,225],"thead",{},[226,227,228,232],"tr",{},[229,230,231],"th",{},"Piece",[229,233,234],{},"Role",[236,237,238,249,263,277,287,303,317],"tbody",{},[226,239,240,246],{},[241,242,243],"td",{},[210,244,245],{},"RepositoryIngestJob",[241,247,248],{},"Everything one sync run needs: repo URL, source kind, filter, run id, trace context. Built once by whoever triggers the run (an endpoint or the scheduler) and carried through unchanged.",[226,250,251,256],{},[241,252,253],{},[210,254,255],{},"IRepositoryIngestDispatcher",[241,257,258,259,262],{},"Runs a job on a specific runtime. Today there's one implementation, ",[210,260,261],{},"InProcessIngestDispatcher",", which runs the whole job inline in the current process.",[226,264,265,270],{},[241,266,267],{},[210,268,269],{},"IIngestWorkspaceProvider",[241,271,272,273,276],{},"Acquires a working directory for the clone. ",[210,274,275],{},"LocalTempWorkspaceProvider"," clones into the OS temp directory and deletes it when the run finishes.",[226,278,279,284],{},[241,280,281],{},[210,282,283],{},"RepositoryIngestRunner",[241,285,286],{},"The actual pipeline: enumerate files, apply the filter, parse and hash each one, upsert, and run a deletion sweep on a clean pass. Knows nothing about git, dispatch, or messaging — it only needs an already-acquired workspace.",[226,288,289,294],{},[241,290,291],{},[210,292,293],{},"IngestFileFilter",[241,295,296,297,302],{},"Decides whether one file path is in scope, given the effective include\u002Fexclude globs. See ",[298,299,301],"a",{"href":300},"#filtering","Filtering"," below.",[226,304,305,314],{},[241,306,307,310,311],{},[210,308,309],{},"PublicRepositorySyncRequestedHandler"," \u002F ",[210,312,313],{},"PrivateRepositorySyncRequestedHandler",[241,315,316],{},"Message consumers that load the source\u002Flibrary, build the job, and call the dispatcher.",[226,318,319,324],{},[241,320,321],{},[210,322,323],{},"IngestSchedulerHostedService",[241,325,326],{},"A background timer that claims sources\u002Flibraries whose next sync is due and publishes sync-requested messages for them, same as a manual trigger would.",[169,328,330],{"id":329},"public-vs-private-sources","Public vs. Private Sources",[220,332,333,345],{},[223,334,335],{},[226,336,337,339,342],{},[229,338],{},[229,340,341],{},"Public source",[229,343,344],{},"Private source",[236,346,347,358,374,393,416,427],{},[226,348,349,352,355],{},[241,350,351],{},"Owned by",[241,353,354],{},"Nobody — shared globally",[241,356,357],{},"One organization's library",[226,359,360,363,368],{},[241,361,362],{},"Documents table",[241,364,365],{},[210,366,367],{},"docs_public_documents",[241,369,370,373],{},[210,371,372],{},"docs_library_documents"," (same table hand-authored docs use)",[226,375,376,379,384],{},[241,377,378],{},"Identified by",[241,380,381],{},[210,382,383],{},"PublicSourceId",[241,385,386,389,390],{},[210,387,388],{},"OrganizationId"," + ",[210,391,392],{},"LibraryId",[226,394,395,398,405],{},[241,396,397],{},"Filter comes from",[241,399,400,401],{},"The source's own default filters ",[402,403,404],"em",{},"(today — see callout below)",[241,406,407,408,411,412,415],{},"The library's own ",[210,409,410],{},"IncludeFilters","\u002F",[210,413,414],{},"ExcludeFilters",", falling back to the source-suggested defaults if empty",[226,417,418,421,424],{},[241,419,420],{},"GitHub auth",[241,422,423],{},"Anonymous clone, or a PAT for rate limits",[241,425,426],{},"GitHub App installation token, resolved per organization",[226,428,429,432,438],{},[241,430,431],{},"Manual trigger endpoint",[241,433,434,437],{},[210,435,436],{},"POST \u002Fapi\u002Fv1\u002Fadmin\u002Fpublic-sources\u002F{publicSourceId}\u002Fingest-run"," (system admin only)",[241,439,440],{},[210,441,442],{},"POST \u002Fapi\u002Fv1\u002Forgs\u002F{orgId}\u002Flibraries\u002F{name}\u002Fingest-run",[164,444,446,447,450],{"icon":445},"i-lucide-info","Public sources are meant to be shared across every subscribing library, with the effective filter being the ",[402,448,449],{},"union"," of every library's filter. That union query doesn't exist yet — today a public source's sync only uses its own default filters. This is a known, documented simplification, not a bug.",[169,452,454],{"id":453},"triggering-a-sync","Triggering a Sync",[174,456,457],{},"A sync can start two ways:",[459,460,461,471],"ol",{},[181,462,463,466,467,470],{},[184,464,465],{},"Manual trigger"," — an HTTP request to one of the endpoints above. Rate-limited (5 triggers per hour per source\u002Flibrary by default) and idempotent (a ",[210,468,469],{},"409"," if a sync is already queued or running).",[181,472,473,476,477,479,480,483,484,486],{},[184,474,475],{},"Scheduled"," — ",[210,478,323],{}," ticks on a timer (5 minutes by default), atomically claims every source\u002Flibrary whose ",[210,481,482],{},"next_sync_at"," has passed, and publishes a sync request for each one. After a run finishes, ",[210,485,482],{}," is set to roughly one hour later with ±20% random jitter, so a fleet of sources doesn't all wake up in lockstep.",[174,488,489],{},"Both paths publish the same kind of message and go through the same handler and runner — a scheduled sync and a manual one are indistinguishable once they're queued.",[169,491,493],{"id":492},"the-clone-two-layers-of-filtering","The Clone: Two Layers of Filtering",[174,495,496],{},"Getting from \"clone the whole repo\" down to \"only the Markdown files that matter\" happens in two separate steps, at two different levels:",[174,498,499,502,503,509,510,513,514,513,517,520,521,524,525,528],{},[184,500,501],{},"1. Git-level narrowing (coarse, extension-only)."," The clone itself uses a ",[298,504,508],{"href":505,"rel":506},"https:\u002F\u002Fgit-scm.com\u002Fdocs\u002Fgit-sparse-checkout",[507],"nofollow","sparse checkout"," restricted to three extensions — ",[210,511,512],{},"*.md",", ",[210,515,516],{},"*.mdc",[210,518,519],{},"*.mdx"," — combined with a partial clone (",[210,522,523],{},"--filter=blob:none",") and shallow history (",[210,526,527],{},"--depth=1","). This means git never downloads file content for anything that isn't a Markdown file, and never downloads more than the latest commit. For a large repository this is the difference between fetching a handful of megabytes and fetching the entire repository history.",[174,530,531,532,535],{},"This step is deliberately ",[402,533,534],{},"not"," directory-aware. It doesn't know or care about your include\u002Fexclude filters — it only narrows by extension.",[174,537,538,541,542,544,545,548,549,552],{},[184,539,540],{},"2. In-process filtering (fine-grained, directory-aware)."," Once the clone lands on disk, ",[210,543,283],{}," walks every Markdown file that survived step 1 and asks ",[210,546,547],{},"IngestFileFilter.IsIncluded"," whether it's actually in scope for ",[402,550,551],{},"this"," sync's configured filter. This is where include globs, exclude globs, and directory targeting apply.",[174,554,555,556,559,560,562],{},"Why split it this way? Translating an arbitrary include\u002Fexclude glob into git's own sparse-checkout pattern language (which has its own dialect, with cone and non-cone modes) is a second glob dialect to get right, for a bandwidth-only benefit. Worst case with the current design: a narrowly-filtered sync's clone briefly materializes some Markdown files on disk that the in-process filter then correctly excludes from the database — it never ",[402,557,558],{},"under","-materializes what correctness requires. ",[210,561,293],{}," is the single source of truth for what actually gets ingested.",[169,564,301],{"id":565},"filtering",[567,568,570],"h3",{"id":569},"syntax","Syntax",[174,572,573,574,577,578,581],{},"A filter is two lists of glob patterns: ",[210,575,576],{},"IncludeGlobs"," and ",[210,579,580],{},"ExcludeGlobs",". The glob dialect is intentionally small — just two wildcards:",[220,583,584,594],{},[223,585,586],{},[226,587,588,591],{},[229,589,590],{},"Wildcard",[229,592,593],{},"Meaning",[236,595,596,615],{},[226,597,598,603],{},[241,599,600],{},[210,601,602],{},"*",[241,604,605,606,611,612,614],{},"Matches anything, of any length — ",[184,607,608,609],{},"including ",[210,610,411],{},". A single ",[210,613,602],{}," can match an entire subtree, not just one path segment.",[226,616,617,622],{},[241,618,619],{},[210,620,621],{},"?",[241,623,624],{},"Matches exactly one character.",[174,626,627,628,631,632,634,635,577,638,641,642,644],{},"There's no special ",[210,629,630],{},"**"," syntax. Because ",[210,633,602],{}," already crosses directory boundaries, ",[210,636,637],{},"docs\u002F*",[210,639,640],{},"docs\u002F**"," would behave identically if ",[210,643,630],{}," existed — so it doesn't.",[174,646,647,648,651,652,655],{},"Matching is case-insensitive and always against the full repository-relative path, normalized to forward slashes with no leading slash (a path like ",[210,649,650],{},".agents\u002Fplans\u002Fnotes.md",", not ",[210,653,654],{},"\u002F.agents\u002Fplans\u002Fnotes.md",").",[567,657,659],{"id":658},"the-two-narrowing-rules-that-always-apply","The Two Narrowing Rules That Always Apply",[174,661,662],{},"Regardless of any configured filter:",[459,664,665,679],{},[181,666,667,668,513,671,674,675,678],{},"Only ",[210,669,670],{},".md",[210,672,673],{},".mdc",", and ",[210,676,677],{},".mdx"," files are ever ingested.",[181,680,681,682,685],{},"An ",[184,683,684],{},"empty"," include list means \"everything\" (subject to rule 1) — it is not the same as \"include nothing.\"",[567,687,689],{"id":688},"include-and-exclude-together","Include and Exclude, Together",[220,691,692,702],{},[223,693,694],{},[226,695,696,699],{},[229,697,698],{},"Step",[229,700,701],{},"Rule",[236,703,704,719,737],{},[226,705,706,709],{},[241,707,708],{},"1. Extension check",[241,710,711,712,411,714,411,716,718],{},"Reject anything that isn't ",[210,713,670],{},[210,715,673],{},[210,717,677],{},", unconditionally.",[226,720,721,724],{},[241,722,723],{},"2. Include check",[241,725,726,727,729,730,733,734,736],{},"If ",[210,728,576],{}," is non-empty, the path must match ",[184,731,732],{},"at least one"," of them (a union — any match is enough). If ",[210,735,576],{}," is empty, this step passes everything through.",[226,738,739,742],{},[241,740,741],{},"3. Exclude check",[241,743,744,745,748,749,751],{},"If the path matches ",[184,746,747],{},"any"," pattern in ",[210,750,580],{},", it's rejected — even if it matched an include pattern in step 2. Exclude always wins.",[567,753,755],{"id":754},"worked-examples","Worked Examples",[174,757,758,759,302],{},"These are real results from dry-running the ingest pipeline against public repositories — see ",[298,760,762],{"href":761},"#dry-run-diagnostics","Dry-Run Diagnostics",[220,764,765,778],{},[223,766,767],{},[226,768,769,772,775],{},[229,770,771],{},"Include globs",[229,773,774],{},"Exclude globs",[229,776,777],{},"What matched",[236,779,780,799,831],{},[226,781,782,787,792],{},[241,783,784],{},[210,785,786],{},"[\".agents\u002Fplans\u002F*\"]",[241,788,789],{},[210,790,791],{},"[]",[241,793,794,795,798],{},"Every Markdown file under ",[210,796,797],{},".agents\u002Fplans\u002F",", at any depth.",[226,800,801,806,810],{},[241,802,803],{},[210,804,805],{},"[\".github\u002Fagents\u002F*\", \".agents\u002Fskills\u002Fd*\"]",[241,807,808],{},[210,809,791],{},[241,811,812,813,513,816,819,820,823,824,513,827,830],{},"Everything under ",[210,814,815],{},".github\u002Fagents\u002F",[184,817,818],{},"plus"," everything under any skill directory whose name starts with ",[210,821,822],{},"d"," (",[210,825,826],{},"dashboard-testing",[210,828,829],{},"dependency-update",", ...). Two include globs are a union, not an intersection — a file only needs to match one of them.",[226,832,833,838,843],{},[241,834,835],{},[210,836,837],{},"[\".github\u002Fagents\u002F*\", \".agents\u002Fskills\u002F*\"]",[241,839,840],{},[210,841,842],{},"[\".agents\u002Fskills\u002Fd*\"]",[241,844,812,845,847,848,851,852,854],{},[210,846,815],{},", plus every skill ",[184,849,850],{},"except"," the ones whose directory starts with ",[210,853,822],{},".",[174,856,857,858,861,862,865,866,868,869,872,873,876,877,879,880,883,884,886],{},"That last example is worth slowing down on, because of one file: ",[210,859,860],{},".agents\u002Fskills\u002Fhosting-integration-authoring\u002Fresources\u002Fdashboard-ux.md",". Its ",[402,863,864],{},"filename"," starts with ",[210,867,822],{}," — but it was still included. The exclude glob ",[210,870,871],{},".agents\u002Fskills\u002Fd*"," matches on the full path starting right after ",[210,874,875],{},".agents\u002Fskills\u002F",", so it only excludes directories that themselves start with ",[210,878,822],{},". ",[210,881,882],{},"hosting-integration-authoring"," doesn't start with ",[210,885,822],{},", so nothing under it is excluded, no matter what the individual filenames look like.",[164,888,890,891,894,895,865,898,900,901,903],{"icon":889},"i-lucide-lightbulb","If you want to exclude by filename rather than by directory, write the glob to match that: ",[210,892,893],{},"*\u002Fd*.md"," would exclude any file whose ",[402,896,897],{},"name",[210,899,822],{},", in any directory, since the leading ",[210,902,602],{}," absorbs the directory path.",[169,905,907],{"id":906},"move-detection","Move Detection",[174,909,910],{},"Every file upsert resolves to exactly one of four outcomes, decided in this order:",[220,912,913,923],{},[223,914,915],{},[226,916,917,920],{},[229,918,919],{},"Outcome",[229,921,922],{},"Condition",[236,924,925,935,945,955],{},[226,926,927,932],{},[241,928,929],{},[184,930,931],{},"Unchanged",[241,933,934],{},"A document already exists at this exact path, and its content hash matches. Only the sync-run stamp is updated — nothing else changes, so unrelated readers don't see spurious churn.",[226,936,937,942],{},[241,938,939],{},[184,940,941],{},"Updated",[241,943,944],{},"A document already exists at this exact path, but the content hash differs.",[226,946,947,952],{},[241,948,949],{},[184,950,951],{},"Moved",[241,953,954],{},"No document exists at this exact path, but exactly one existing document (scoped to this source\u002Flibrary) has the same content hash. The old path is appended to that document's history, and its path is updated to the new one.",[226,956,957,962],{},[241,958,959],{},[184,960,961],{},"Added",[241,963,964],{},"Nothing above matched.",[174,966,967,968,970],{},"If two or more existing documents share the same content hash as an incoming file with no path match (for example, two files that happen to be byte-for-byte identical), the ambiguous case falls through to ",[184,969,961],{}," rather than guessing which one moved. An exact path match always takes priority over a hash match, so this ambiguity only ever affects genuine moves where the destination content also happens to collide with something else in the same source.",[174,972,973],{},"After every file in a sync has been processed with zero failures, a deletion sweep removes any document in that source\u002Flibrary that wasn't touched by this run's stamp — it's no longer present upstream. If even one file failed to process, the sweep is skipped entirely for that run, so a partial failure never causes correct documents to be deleted because the run couldn't prove they were actually gone.",[169,975,762],{"id":976},"dry-run-diagnostics",[174,978,979,980,983],{},"Because a real sync writes to the database, testing filter behavior against a real repository used to mean either accepting real writes or writing a one-off script. ",[210,981,982],{},"Zeeq.Platform.Ingest.Diagnostics"," provides a permanent way to run the real pipeline — real clone, real parsing, real reads against existing data for accurate move detection — with all writes only logged, never persisted.",[174,985,986,987,990],{},"This is meant to be run through the ",[210,988,989],{},"zeeq-dotnet-repl"," skill against a live local server, not called from application code. It's how the worked examples above were produced: a real clone of a real public repository, filtered, walked, and logged, with nothing landing in Postgres afterward.",[169,992,994],{"id":993},"the-library-ui","The Library UI",[174,996,997,998,1001],{},"The Libraries view's create\u002Fedit slideover (",[210,999,1000],{},"LibraryFormSlideover.vue",") is how an organization actually sets up repository-sourced libraries, rather than calling the endpoints above directly.",[174,1003,1004,1007,1008,1011,1012,1015,1016,1019,1020,411,1022,1025],{},[184,1005,1006],{},"Create."," An \"Import from GitHub\" switch reveals a source picker with two tabs: ",[184,1009,1010],{},"Public"," (a free-text GitHub URL — creates or reuses a ",[210,1013,1014],{},"docs_public_sources"," row keyed by normalized repo URL) and ",[184,1017,1018],{},"Private"," (a picker restricted to repositories already configured for the organization's GitHub App installation, since a private clone needs an installation token). Both tabs expose the same include\u002Fexclude filter text areas as the manual-library form. Submitting immediately follows up with a call to the same trigger-ingest endpoint the \"Sync now\" button uses, so the first sync queues without a separate user action — a ",[210,1021,469],{},[210,1023,1024],{},"429"," from that follow-up call (already in flight or rate-limited) is swallowed into an informational toast rather than failing the create.",[174,1027,1028,1031],{},[184,1029,1030],{},"Edit."," Once a library exists, the slideover becomes tabbed:",[220,1033,1034,1047],{},[223,1035,1036],{},[226,1037,1038,1041,1044],{},[229,1039,1040],{},"Tab",[229,1042,1043],{},"Shown when",[229,1045,1046],{},"Contents",[236,1048,1049,1060,1079],{},[226,1050,1051,1054,1057],{},[241,1052,1053],{},"Library",[241,1055,1056],{},"Always",[241,1058,1059],{},"Name, description, repository mappings, and (for a source-backed library) a read-only source summary plus editable include\u002Fexclude filters. The repo URL and source kind can never be edited here — see below.",[226,1061,1062,1065,1068],{},[241,1063,1064],{},"Sync status",[241,1066,1067],{},"Source-backed only",[241,1069,1070,1071,1074,1075,1078],{},"Current ",[210,1072,1073],{},"syncStatus",", last\u002Fnext sync timestamps, quarantine warning if applicable, a \"Sync now\" button, and a cursor-paginated run history (10 per page, ",[210,1076,1077],{},"GET \u002Forgs\u002F{orgId}\u002Flibraries\u002F{name}\u002Fingest-runs","). The slideover polls the library every 3s while a sync is queued or running, and stops once it settles.",[226,1080,1081,1084,1086],{},[241,1082,1083],{},"Delete",[241,1085,1056],{},[241,1087,1088,1089,1091],{},"Switch-gated (\"Enable deletion\") plus an exact-name-confirmation input before the delete button enables — mirrors other destructive-action confirmations in the app. Deleting a private-source library removes it and its documents outright; deleting a library that subscribes to a public source only unsubscribes that library — the shared ",[210,1090,367],{}," rows remain for any other organization still subscribed to the same source.",[174,1093,1094],{},"A source-backed library's repo URL and source kind are permanently fixed at creation. There is no \"change the URL\" affordance anywhere in the edit form — the intended path to point a library at a different repository is to delete it and create a new one, which also avoids having to reconcile move\u002Frename detection across two different upstream repositories.",[174,1096,1097,1098,1101,1102,1105,1106,1109],{},"The document editor (",[210,1099,1100],{},"md-editor-v3",") is read-only for any document whose ",[210,1103,1104],{},"origin"," resolves to ",[210,1107,1108],{},"\"remote\""," — which covers every document that came from a sync, both public- and private-sourced. Hand-authored documents in a plain (non-source-backed) library remain fully editable.",[169,1111,1113],{"id":1112},"known-gaps","Known Gaps",[178,1115,1116,1122,1128,1145],{},[181,1117,1118,1121],{},[184,1119,1120],{},"Public-source union filters (planned, not built)."," A public source's effective filter should be the union of every subscribing library's filter. Today it only uses the source's own defaults.",[181,1123,1124,1127],{},[184,1125,1126],{},"Public visibility re-verification (planned, not built)."," A public source that goes private upstream should be detected and quarantined before its content is ever confused with a repository Zeeq no longer has permission to read. Not implemented yet.",[181,1129,1130,1133,1134,1137,1138,411,1141,1144],{},[184,1131,1132],{},"Bounded concurrency is coarse."," Each source kind has its own message channel with a fixed number of concurrent workers (",[210,1135,1136],{},"noOfPerformers",", a compile-time constant matching ",[210,1139,1140],{},"IngestSettings.MaxConcurrentPublic",[210,1142,1143],{},"MaxConcurrentPrivate","'s defaults). If those settings are ever tuned without a matching code change, the two will drift.",[181,1146,1147,1153,1154,1157,1158,1160],{},[184,1148,1149,1150,854],{},"A rare failure can strand a source at ",[210,1151,1152],{},"running"," If the final write that resets a source back to ",[210,1155,1156],{},"idle"," fails, nothing else resets it — the scheduler only ever claims ",[210,1159,1156],{}," sources. Documented as an accepted, low-probability gap rather than fixed, since there's no real production traffic yet to justify the extra machinery.",{"title":208,"searchDepth":1162,"depth":1162,"links":1163},2,[1164,1165,1166,1167,1168,1169,1170,1177,1178,1179,1180],{"id":171,"depth":1162,"text":172},{"id":199,"depth":1162,"text":200},{"id":217,"depth":1162,"text":218},{"id":329,"depth":1162,"text":330},{"id":453,"depth":1162,"text":454},{"id":492,"depth":1162,"text":493},{"id":565,"depth":1162,"text":301,"children":1171},[1172,1174,1175,1176],{"id":569,"depth":1173,"text":570},3,{"id":658,"depth":1173,"text":659},{"id":688,"depth":1173,"text":689},{"id":754,"depth":1173,"text":755},{"id":906,"depth":1162,"text":907},{"id":976,"depth":1162,"text":762},{"id":993,"depth":1162,"text":994},{"id":1112,"depth":1162,"text":1113},"How Zeeq pulls Markdown documentation out of public and private GitHub repositories and turns it into searchable library documents.","md",null,{"icon":1185},"i-lucide-download",true,{"title":151,"description":1181},"j7hDrkjvdfqBJitc19ZGU6Cno9ZkpI1f-GVzYC8I2F0",[1190,1192],{"title":146,"path":147,"stem":148,"description":1191,"icon":149,"children":-1},"How local coding agents upload diffs and run the shared code-review agents through MCP.",{"title":155,"path":156,"stem":157,"description":1193,"children":-1},"Ingest and processing of OpenTelemetry data from agent harnesses.",1784297365800]