Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d80d41b
chore(release): v3.0.1 - audit fixes, chunk mermaid, font FOIT, SEO, …
mbayue Sep 8, 2026
4f30fc6
fix(workspace): correct sidebar modes and bump to v3.0.2
mbayue Sep 8, 2026
f1c226b
feat(privacy): add disclosures and prerender public pages
mbayue Sep 8, 2026
7780620
fix: make repository enrichment resilient and resolve review regressions
mbayue Sep 8, 2026
85404c4
fix(search): isolate snapshots and bound indexing resources
mbayue Sep 8, 2026
2ef3e1a
feat(search): add resumable indexing and bounded provider usage
mbayue Sep 12, 2026
59f7659
fix(cache): isolate repository analysis by credentials
mbayue Sep 12, 2026
2237b69
feat(a11y): add persistent motion preferences
mbayue Sep 12, 2026
4611312
feat(site): add policies and consistent navigation
mbayue Sep 12, 2026
a9ff669
feat(ai): unify providers, add custom endpoint settings, and harden t…
mbayue Sep 12, 2026
2332b20
chore(release): bump version to v3.5.0 and update documentation
mbayue Sep 12, 2026
4c9d3df
chore(docs): remove unreferenced resumable-search design doc
mbayue Sep 12, 2026
b0a1664
fix(parser): support PEP 621 arrays and Poetry tables in pyproject.to…
mbayue Sep 13, 2026
dc867d0
fix: resolve review findings across search, AI tooling, manifest pars…
mbayue Sep 13, 2026
167c6ca
fix: resolve review findings on simulation stability, queue abortion,…
mbayue Sep 13, 2026
32d4080
fix: bump version to 3.5.4 and enhance abort handling in bounded queue
mbayue Sep 13, 2026
13cbbd3
fix: detach bounded-queue caller-abort listener, add SSRF guard, reso…
mbayue Sep 13, 2026
28c8aae
fix: harden limiter DNS resolution, guard IPv6 transition prefixes, r…
mbayue Sep 13, 2026
66e2ffb
fix: expand SSRF guard IPv6 decoding, bound limiter DNS lookup, unify…
mbayue Sep 14, 2026
2628a4d
fix(security): enforce strict IPv6 compression and hextet validation …
mbayue Sep 14, 2026
28e07d5
fix(ai): invalidate mutations on revision bump, trigger canvas redraw…
mbayue Sep 14, 2026
7440d1e
docs: clamp changelog by release date, sync architecture subsystems, …
mbayue Sep 14, 2026
af988b7
Update AGENTS.md
mbayue Sep 14, 2026
0fe8043
Update server/dev-api.ts
mbayue Sep 14, 2026
6bc13c0
Update server/dev-api.ts
mbayue Sep 14, 2026
700c201
fix(dev): remove extra brace in dev-api middleware and record workspa…
mbayue Sep 14, 2026
c0620c8
fix(reliability): harden provider requests and repository state
mbayue Sep 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 25 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,36 +1,56 @@
# GitHub API (optional, increases rate limits for public repos)
GITHUB_TOKEN=

# AI provider: gemini | openai | anthropic | edgeone | mock
# AI provider: gemini | openai | anthropic | mock
AI_PROVIDER=mock
# Optional separate provider for semantic search: openai, gemini, or mock.
# EMBEDDING_PROVIDER=openai
# Independent embedding credentials and endpoint (recommended).
# Legacy OPENAI_/GEMINI_ settings are used when these are absent.
# EMBEDDING_API_KEY=
# EMBEDDING_API_BASE=https://api.openai.com/v1
# EMBEDDING_MODEL=text-embedding-3-small
# OpenAI-compatible example: OPENAI_API_BASE=https://api.featherless.ai/v1
# OPENAI_EMBEDDING_MODEL=Qwen/Qwen3-Embedding-8B
# EMBEDDING_DIMENSIONS=4096

Comment on lines +14 to 16

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The new OpenAI-compatible example duplicates two variable names already defined later in this same file: it proposes # OPENAI_EMBEDDING_MODEL=Qwen/Qwen3-Embedding-8B and # EMBEDDING_DIMENSIONS=4096, while lines 33-35 still declare OPENAI_EMBEDDING_MODEL=openrouter/openai/text-embedding-3-large and EMBEDDING_DIMENSIONS=3072. A user following the example by uncommenting the top block will have both assignments in the file, and the later ones win when the env is loaded (server/env.ts uses Vite loadEnv/dotenv, last assignment wins), so the Qwen/4096 settings are silently ignored. Worse, if only EMBEDDING_DIMENSIONS=4096 is uncommented while text-embedding-3-large stays active, the 4096 output dimensionality exceeds that model's 3072 maximum and embedding calls fail. Make the example self-contained: have it reference the EMBEDDING_MODEL=/EMBEDDING_DIMENSIONS= pair only once, and add an explicit note that the legacy OPENAI_EMBEDDING_MODEL/EMBEDDING_DIMENSIONS lines below must be removed or commented out, or drop the duplicated variables from the example entirely.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .env.example, line 14:

<comment>The new OpenAI-compatible example duplicates two variable names already defined later in this same file: it proposes `# OPENAI_EMBEDDING_MODEL=Qwen/Qwen3-Embedding-8B` and `# EMBEDDING_DIMENSIONS=4096`, while lines 33-35 still declare `OPENAI_EMBEDDING_MODEL=openrouter/openai/text-embedding-3-large` and `EMBEDDING_DIMENSIONS=3072`. A user following the example by uncommenting the top block will have both assignments in the file, and the later ones win when the env is loaded (server/env.ts uses Vite loadEnv/dotenv, last assignment wins), so the Qwen/4096 settings are silently ignored. Worse, if only `EMBEDDING_DIMENSIONS=4096` is uncommented while `text-embedding-3-large` stays active, the 4096 output dimensionality exceeds that model's 3072 maximum and embedding calls fail. Make the example self-contained: have it reference the `EMBEDDING_MODEL=`/`EMBEDDING_DIMENSIONS=` pair only once, and add an explicit note that the legacy `OPENAI_EMBEDDING_MODEL`/`EMBEDDING_DIMENSIONS` lines below must be removed or commented out, or drop the duplicated variables from the example entirely.</comment>

<file context>
@@ -1,36 +1,56 @@
+# EMBEDDING_API_BASE=https://api.openai.com/v1
+# EMBEDDING_MODEL=text-embedding-3-small
+# OpenAI-compatible example: OPENAI_API_BASE=https://api.featherless.ai/v1
+# OPENAI_EMBEDDING_MODEL=Qwen/Qwen3-Embedding-8B
+# EMBEDDING_DIMENSIONS=4096
 
</file context>
Suggested change
# OPENAI_EMBEDDING_MODEL=Qwen/Qwen3-Embedding-8B
# EMBEDDING_DIMENSIONS=4096
# OpenAI-compatible example (overrides EMBEDDING_MODEL/EMBEDDING_DIMENSIONS below):
# EMBEDDING_MODEL=Qwen/Qwen3-Embedding-8B
# EMBEDDING_DIMENSIONS=4096
# Note: if you enable these, comment out or remove the legacy
# OPENAI_EMBEDDING_MODEL and EMBEDDING_DIMENSIONS lines below, otherwise the
# later assignments override this example.

# AI API Key (mandatory)
GEMINI_API_KEY=
OPENAI_API_KEY=
ANTHROPIC_API_KEY=
EDGEONE_API_KEY=

# Model overrides (optional)
GEMINI_MODEL=gemini-2.5-flash
GEMINI_API_VERSION=v1alpha
OPENAI_MODEL=gpt-4o-mini
ANTHROPIC_MODEL=claude-3-5-haiku-latest
EDGEONE_MODEL=@makers/deepseek-v4-flash

# Provider API base URL overrides (optional)
OPENAI_API_BASE=
ANTHROPIC_API_BASE=
EDGEONE_API_BASE=https://ai-gateway.edgeone.link/v1

# Embedding overrides (optional)
OPENAI_EMBEDDING_MODEL=openrouter/openai/text-embedding-3-large
EDGEONE_EMBEDDING_MODEL=openrouter/openai/text-embedding-3-large
GEMINI_EMBEDDING_MODEL=gemini-embedding-001
EMBEDDING_DIMENSIONS=3072

# Cache key hashing secret (optional, set a stable random value in production)
# Required in shared mode (including when Redis is configured). Use a random secret.
# Local mode generates a process-only secret when this is blank.
TOKEN_CACHE_HASH_SECRET=

# Production server binding (optional)
HOST=0.0.0.0
PORT=3000

# Daily embedding input budget (300 MB; non-refundable reservation per attempt).
# In the default local mode this budget is PER-PROCESS: each instance enforces its own 300 MB.
# To share one budget across instances, use shared-mode rate limiting:
# RATE_LIMIT_MODE=shared plus UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN.
SERVER_EMBEDDING_DAILY_BYTES=300000000

API_REQUESTS_PER_MINUTE=600

SERVER_AI_DAILY_CALLS=500

API_REQUESTS_PER_IP_PER_MINUTE=120
92 changes: 56 additions & 36 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## Project Identity

**gitSdm** (Git Software Dependency Map) — v3.0.0. Graph-first repository analysis tool: visualize file dependencies, AI-powered codebase insights, semantic search, commit timelines, architecture diagrams, and dependency health. Single-page app with an embedded Express backend + Vercel serverless functions.
**gitSdm** (Git Software Dependency Map) — v3.5.11. Interactive repository dependency visualization tool: map file dependencies, AI-powered codebase insights, semantic search, commit timelines, architecture diagrams, and dependency health. Single-page app with an embedded Express backend + Vercel serverless functions.

---

Expand All @@ -20,7 +20,7 @@
| Graph Viz | react-force-graph-2d, d3-force, d3-hierarchy |
| Diagrams | Mermaid 11, html-to-image, jsPDF |
| Backend | Express (dev + prod server), Zod validation |
| AI Providers | Gemini, OpenAI, Anthropic, EdgeOne Makers, Mock — unified via `createProvider()` |
| AI Providers | Gemini, OpenAI, Anthropic, Mock — unified via `createProvider()` |
| GitHub API | Octokit REST v21 |
| Search | In-memory vector store with chunking + embedding + QA engine |
| Security | dompurify (sanitization) |
Expand All @@ -35,15 +35,15 @@
gitSdm/
├── api/ # Vercel serverless entry points (thin wrappers)
│ ├── ai/ # AI endpoint wrappers
│ ├── repo/ # Repo API endpoint wrappers
│ ├── repo/ # Repo API endpoint wrappers (analyze, files, branches, churn, health)
│ └── trending.ts # Trending repos endpoint
├── server/ # Backend services & router
│ ├── ai/ # AI provider abstraction + task handlers
│ ├── ai/ # AI provider abstraction, chat config, SSRF protection, prompts & tasks
│ │ ├── prompts.ts # Shared AI prompt templates
│ │ ├── provider.ts/test.ts # AI provider (Gemini/OpenAI/Anthropic/EdgeOne/Mock)
│ │ ├── provider.ts/test.ts # AI provider (Gemini/OpenAI/Anthropic/Mock)
│ │ ├── service.ts/test.ts # AI service orchestration
│ │ └── tasks/ # Individual AI tasks (diagram, explain, onboarding, playground, refactor)
│ ├── cache/ # LRU caching layer (lru.ts/test.ts)
│ ├── cache/ # LRU caching layer & hashed token secrets
│ ├── config/ # Env validation & public config (app-config.ts/test.ts)
│ ├── env.ts # Environment variable exports
│ ├── github/ # GitHub API client (Octokit), fetch-tree, mock-data (+ test files)
Expand All @@ -53,51 +53,51 @@ gitSdm/
│ │ ├── dependency-analyzer.ts/test.ts
│ │ ├── file-classifier.ts/test.ts
│ │ ├── import-resolver.ts/test.ts
│ │ └── manifest-parsers/ # docker, go, java, npm, pip, rust + shared registry/types
│ │ └── manifest-parsers/ # docker, go, java, npm, pip (PEP 621/Poetry), rust + shared registry/types
│ ├── router/ # Route handlers (ai-routes, repo-routes, search-routes, schemas)
│ ├── search/ # Semantic search: chunker, embeddings, vector store, QA engine, indexing pipeline
│ ├── services/ # Business logic (analyze-repo, churn-service, dependency-health, get-file, npm-registry, trending)
│ ├── utils/ # Errors, context, logger, HTTP helpers
│ ├── search/ # Semantic search: chunker, embeddings, checkpoints, vector store, QA engine, indexing pipeline
│ ├── services/ # Business logic (analyze-repo, churn-service, dependency-health, repo-enrichment, get-file, npm-registry, trending)
│ ├── utils/ # Errors, context, logger, HTTP, limits, SSRF guard, bounded queue
│ ├── api-router.ts # Unified API router
│ ├── dev-api.ts # Dev server API middleware
│ ├── dev-api.ts # Vite dev server middleware
│ ├── prod-server.ts # Production Express server
│ └── vercel-handler.ts # Vercel serverless entry
├── src/ # Frontend SPA
│ ├── app/ # Router setup (router.tsx), app providers (providers.tsx)
│ ├── components/ # UI components organized by domain
│ │ ├── ui/ # shadcn primitives & Base UI wrappers
│ │ ├── ui/ # shadcn primitives, button-variants & Base UI wrappers
│ │ ├── viz/ # Main workspace: ai-sidebar/, architecture/, layout/, learning-path/, top-nav/
│ │ │ ├── ai-sidebar/ # AI center tab, action buttons, intelligence cards, tool cards
│ │ │ ├── architecture/ # Mermaid diagram generation, pan/zoom, render-sequence guard
│ │ │ ├── layout/ # VizSidebar & panel drawers
│ │ │ ├── learning-path/# Guided code walkthroughs
│ │ │ ├── top-nav/ # TopNav, BranchSwitcher, HeaderActionMenu, HeaderStats, WorkspaceModeSelector
│ │ │ ├── AIErrorCard.tsx, AISidebar.tsx, AnalysisTab.tsx, ArchitectureView.tsx
│ │ │ ├── BottomStatusBar.tsx, DependencyHealthTab.tsx, LearningPathTab.tsx
│ │ │ ├── OverviewTab.tsx, SettingsPopover.tsx, StagedLoader.tsx, VizError.tsx
│ │ │ ├── BottomStatusBar.tsx, ChurnStatus.tsx, DependencyHealthTab.tsx, LearningPathTab.tsx
│ │ │ ├── MotionSettings.tsx, OverviewTab.tsx, SettingsPopover.tsx, StagedLoader.tsx, VizError.tsx
│ │ ├── explorer/ # File explorer sidebar + code inspector dock
│ │ ├── timeline/ # Commit history view + repo timeline
│ │ ├── contributors/# Contributor analytics
│ │ ├── home/ # Landing page: HeroSection, RepoInput, HomeGraphPreview, Trending, repoPresets
│ │ ├── layout/ # Navbar
│ │ ├── contributors/# Contributor analytics & timeline layout
│ │ ├── home/ # Landing page: HeroSection, RepoInput, HomeGraphPreview, Trending, repoPresets, repo-navigation
│ │ ├── layout/ # Navbar, SiteFooter, InfoPageLayout, PageMetadata
│ │ ├── theme/ # ThemeSync
│ │ └── ErrorBoundary.tsx
│ ├── features/ # Feature modules
│ │ ├── graph/ # Graph canvas (ForceGraphCanvas, GraphCanvas, ToolbarDropdowns), widgets, force engine
│ │ │ ├── canvas/ # Canvas layout engine, hooks, helpers (filters), widgets (DropdownPanel, LegendPanel)
│ │ │ └── force/ # Force constants, color palettes, blastRadius, buildForceGraphData
│ │ ├── ai/ # AI task frontend hooks (useAiTasks)
│ │ └── search/ # Semantic search UI: SearchBar, SearchResults, QAAnswerView, IndexingStatusPanel
│ ├── hooks/ # Shared hooks (useAnalyzeRepo, useCodeInspectorState, useMobile, useRepoBranches, useRepoTags, useWorkspaceShortcuts)
│ ├── lib/ # Shared utilities: apiClient, clipboard, utils, file-context (+ test files)
│ ├── stores/ # Zustand stores (vizStore — canonical global store)
│ ├── pages/ # Route pages (VizPage, HomePage, SearchPage, NotFoundPage)
│ ├── types/ # TypeScript type definitions (api, domain, github, index)
│ │ │ └── force/ # Force constants, color palettes, blastRadius, buildForceGraphData, reconcileGraph
│ │ ├── ai/ # AI task frontend hooks & task cache (useAiTasks, tool-cache)
│ │ └── search/ # Semantic search UI: SearchBar, SearchResults, SearchIndexControls, SearchEmptyState, QAAnswerView, IndexingStatusPanel
│ ├── hooks/ # Shared hooks (useAnalyzeRepo, useCodeInspectorState, useMobile, useRepoBranches, useRepoTags, useWorkspaceShortcuts, useMotionPreference, useRepoChurn, useRepoHealth)
│ ├── lib/ # Shared utilities: apiClient, clipboard, utils, file-context, motion-preference, page-metadata, churn-progress, workspace-mode (+ test files)
│ ├── stores/ # Zustand stores (vizStore, motionStore, chatConfigStore)
│ ├── pages/ # Route pages (HomePage, VizPage, SearchPage, TermsPage, PrivacyPage, NotFoundPage, search-page-logic)
│ ├── types/ # TypeScript type definitions (api, domain, github, churn, index)
│ ├── styles/ # Tailwind CSS global styles (globals.css, interface.css)
│ └── main.tsx # App entry point
├── e2e/ # Playwright end-to-end test specs (offline mock-driven)
└── public/ # Static assets
```
├── public/ # Static assets (og-image.png/svg, robots.txt, sitemap.xml)
├── scripts/ # Prerender and maintenance scripts (prerender.tsx, clean_graphify.py)
└── e2e/ # Playwright end-to-end test specs (offline mock-driven)

---

Expand All @@ -108,7 +108,7 @@ gitSdm/
All AI interactions go through `server/ai/provider.ts`. Do NOT call SDKs directly in task code.

```text
Task handler → summarizer / task → createProvider(type) → { Gemini | OpenAI | Anthropic | EdgeOne | Mock }
Task handler → summarizer / task → createProvider(type) → { Gemini | OpenAI | Anthropic | Mock }
```

- Uses `createProvider(overrideKey?)` → returns `AIProvider` with `.complete(messages, options?)`
Expand All @@ -133,7 +133,7 @@ Manual pathname-matching pattern in `server/router/`. Route files export `handle

### API Client (Frontend)

`src/lib/apiClient.ts` — Typed fetch wrapper via `apiFetch<T>(url, options?)`. Authentication tokens stored in `localStorage` (`gitsdm_gemini_api_key`, `gitsdm_github_pat`) and sent as `X-Gemini-API-Key` / `X-GitHub-Token` headers.
`src/lib/apiClient.ts` — Typed fetch wrapper via `apiFetch<T>(url, options?)`. Authentication tokens stored in `localStorage` (`gitsdm_gemini_api_key`, `gitsdm_github_pat`) and sent as `X-AI-API-Key` (with `X-Gemini-API-Key` fallback) / `X-GitHub-Token` headers.

### Toast Notification Pattern

Expand Down Expand Up @@ -189,7 +189,7 @@ Test runner: **Bun** (`bun test --isolate`).

### Coverage & Test Counts

- **46 test files, 408 tests passing** (991 expect calls), 0 failures.
- **78 test files, 527 tests passing** (1479 expect calls), 0 failures.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Custom agent: Flag AI Slop and Fabricated Changes

This added test-count claim is stale: the checkout has 79 unit-test files and 11 E2E specs with 42 E2E tests, while this line and the E2E section report different totals. Run the current suites and update all documented counts together.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At AGENTS.md, line 192:

<comment>This added test-count claim is stale: the checkout has 79 unit-test files and 11 E2E specs with 42 E2E tests, while this line and the E2E section report different totals. Run the current suites and update all documented counts together.</comment>

<file context>
@@ -189,7 +189,7 @@ Test runner: **Bun** (`bun test --isolate`).
 ### Coverage & Test Counts
 
-- **46 test files, 408 tests passing** (991 expect calls), 0 failures.
+- **78 test files, 527 tests passing** (1479 expect calls), 0 failures.
 - Run a single test file: `bun test src/components/home/RepoInput.test.ts`
 - Run test coverage: `bun test --coverage`
</file context>

- Run a single test file: `bun test src/components/home/RepoInput.test.ts`
- Run test coverage: `bun test --coverage`

Expand Down Expand Up @@ -225,22 +225,18 @@ bun run lint # ESLint check
| Variable | Default | Description |
| ------------------------ | ------------------------------------------ | -------------------------------------- |
| `GITHUB_TOKEN` | — | GitHub PAT for API rate limits |
| `AI_PROVIDER` | `mock` | Provider: gemini, openai, anthropic, edgeone, mock |
| `AI_PROVIDER` | `mock` | Provider: gemini, openai, anthropic, mock |
| `GEMINI_API_KEY` | — | Gemini API key |
| `OPENAI_API_KEY` | — | OpenAI API key |
| `ANTHROPIC_API_KEY` | — | Anthropic API key |
| `EDGEONE_API_KEY` | — | EdgeOne Makers Models API key (alias: `MAKERS_MODELS_KEY`) |
| `OPENAI_API_BASE` | OpenAI default | Custom API base URL |
| `ANTHROPIC_API_BASE` | Anthropic default | Custom API base URL |
| `EDGEONE_API_BASE` | `https://ai-gateway.edgeone.link/v1` | EdgeOne API base URL |
| `OPENAI_EMBEDDING_MODEL` | `openrouter/openai/text-embedding-3-large` | Embedding model |
| `EDGEONE_EMBEDDING_MODEL`| `openrouter/openai/text-embedding-3-large` | Embedding model |
| `EMBEDDING_DIMENSIONS` | `3072` | Vector dimension count |
| `GEMINI_MODEL` | `gemini-2.5-flash` | Gemini model override |
| `GEMINI_API_VERSION` | `v1alpha` | Gemini API version |
| `OPENAI_MODEL` | `gpt-4o-mini` | OpenAI model override |
| `ANTHROPIC_MODEL` | `claude-3-5-haiku-latest` | Anthropic model override |
| `EDGEONE_MODEL` | `@makers/deepseek-v4-flash` | EdgeOne model override |
| `GEMINI_EMBEDDING_MODEL` | `gemini-embedding-001` | Gemini embedding model override |
| `TOKEN_CACHE_HASH_SECRET`| — | Cache key hashing secret (production) |
| `HOST` | `0.0.0.0` | Production server bind |
Expand All @@ -257,8 +253,32 @@ bun run lint # ESLint check
- Zero hardcoded secrets
- 250+ LOC ceiling approached only by generated shadcn components

## Versioning Policy

Version numbers increment progressively based on commit scope and change size:

- **Major (`+1.x.x`)**: Major milestone or large-scale overhaul (100+ files).
- **Minor (`x.+1.x`)**: Feature additions and substantial enhancements (`feat`).
- **Patch (`x.x.+1`)**: Bug fixes, security hardening, and maintenance (`fix`, `chore`).

Track progressive increments across commit batches rather than collapsing multiple feature commits into a single minor bump. Releases on the same date are consolidated in the changelog under that date's latest version.

## CI Requirements

- `.github/workflows/ci.yml`: Pinned Bun 1.3.14 (`setup-bun`), `permissions: contents: read`.
- All installs use `nick-invision/retry@v3` with `bun install --frozen-lockfile`.
- Jobs: `lint` -> `typecheck` -> `test` -> `build` (with 2.5 MB gzipped-JS bundle gate) -> `e2e` (`AI_PROVIDER=mock`).

## Agent skills

### Issue tracker

Issues live as local markdown files under `.scratch/`. See `docs/agents/issue-tracker.md`.

### Triage labels

Default five canonical triage roles. See `docs/agents/triage-labels.md`.

### Domain docs

Single-context layout (`CONTEXT.md` + `docs/adr/`). See `docs/agents/domain.md`.
Loading
Loading