# Repository Guidelines

## Agent Workflow Policy (Important)
- Propose-first: Always propose a brief plan and options before making any code changes.
- Confirm scope: Get user confirmation on scope, priorities, and sequencing.
- Minimal diffs: When approved, implement the smallest focused changes consistent with the repo’s style.
- Checkpoints: Share intermediate summaries for multi-step work; pause for feedback before large or risky edits.
- No surprises: Avoid adding dependencies, changing interfaces, or touching unrelated files without explicit approval.
- Safety: Prefer read/inspect commands first; run tests and validations after implementing approved changes.

## Project Structure & Module Organization
- `src/`: Primary source code (modules/packages by feature).
- `tests/`: Mirrors `src/` structure for unit/integration tests.
- `docs/`: Architecture notes, ADRs, and usage guides.
- `scripts/`: Developer utilities (formatting, release, CI helpers).
- `.github/workflows/`: CI pipelines and required checks.
- `packages/` (optional, monorepo): Independent libraries/services.

## Build, Test, and Development Commands
Use a Makefile to standardize workflows across stacks:
- `make setup`: Install toolchain and dependencies (wraps `npm i`, `pip install -r`, or `cargo build` as appropriate).
- `make build`: Compile or type-check the project.
- `make test`: Run the full test suite with coverage.
- `make lint` / `make format`: Lint and auto-format code.
- `make dev` / `make run`: Start a local dev server or binary.
If a Makefile is absent, prefer: `npm test`, `npm run build`, `pytest -q`, or `cargo test` depending on language.

## Coding Style & Naming Conventions
- Indentation: 2 spaces for JS/TS; 4 for Python; tabs avoided.
- Line length: target 100 cols; wrap thoughtfully.
- Filenames: `kebab-case` for JS/TS, `snake_case.py` for Python. Classes use `PascalCase`; functions/vars use `camelCase` (TS/JS) or `snake_case` (Python).
- Tools: Prettier + ESLint (TS/JS), Black + Ruff (Python). Provide `.editorconfig` for universal basics.

## Testing Guidelines
- Frameworks: Vitest/Jest (TS/JS), Pytest (Python). Prefer fast, isolated unit tests.
- Layout: `tests/<module>/...` with names like `*.test.ts` or `test_*.py`.
- Coverage: maintain ≥90% on changed lines; add regression tests for bugs.
- Run locally: `make test` or `npm test` / `pytest`.

## Commit & Pull Request Guidelines
- Commits: Conventional Commits (e.g., `feat: add config loader`, `fix: handle empty payload`). Scope optional but encouraged.
- PRs: clear description, linked issues (`Closes #123`), screenshots for UI, steps to verify, and checklist for docs/tests.
- CI must pass; no failing lints or decreased coverage.

## Security & Configuration Tips
- Do not commit secrets. Use `.env` (local) and keep `.env.example` updated.
- Rotate API keys; pin dependencies; run `npm audit`/`pip-audit` in CI.
- Review third-party code and license compatibility before adding dependencies.

## Project Preferences (MCP Merchant)
- Namespace: `ai.shawndurrani/mcp-merchant` (DNS ownership verified)
- Registry path: NPM package with `stdio` transport first; add hosted `remotes` (SSE) later
- Data source (MVP): Stripe Products/Prices in test mode; cache in-memory
- UI/Hosting: Railway for optional Next.js demo and future SSE endpoint at `mcp.shawndurrani.ai`
- Tool surface (MVP): `searchProducts`, `health`; add cart/checkout later
- Safety: No PII, Stripe test mode only, query and page size limits

## New: MCP Registry Service (SSE‑only)
- Name/namespace: `ai.shawndurrani/mcp-registry`
- Location: separate repo alongside this project (SSE server only; no stdio needed).
- Transport/endpoints: `GET /sse`, `POST /message`, `GET /healthz`.
- Tools (runtime): `health`, `searchServers` (cursor + aggregation), `getServer`, `probeSse`, `makeClientConfig`, `listAllServers`, `countServers`.
- Safety caps: query ≤ 120 chars, `pageSize` ≤ 50, short request timeouts, small in‑memory cache, gentle rate limits on `/sse` and `/message`.
- Hosting notes (Railway + Cloudflare):
  - Public Networking ON; start command `node src/http_server.js`.
  - Healthcheck path `/healthz` (note the trailing z).
  - Cloudflare DNS for the subdomain should be “DNS only” (no proxy) for reliable SSE; bypass cache on `/sse`, `/message`, `/healthz`.
  - Custom domain example: `https://mcp-registry.shawndurrani.ai/sse`.

## Explorer (/public/explore)
- Location: now served by the mcp‑registry service (same‑origin with data) at `https://mcp-registry.shawndurrani.ai/explore`. The mcp‑merchant service redirects `/explore` to this URL.
- Stack: static HTML + vanilla JS, styled with prebuilt Tailwind CSS (no runtime build in production).
- UX behaviour:
  - Snapshot‑first listing (latest‑only); infinite scroll aggregates multiple registry pages under the hood to fill the UI chunk size.
  - The same‑origin `/registry` proxy sets `version=latest` to avoid duplicate historical entries.
  - Controls: SSE toggle, Active‑only, sort by Name or Version; status shows page item count and snapshot freshness.
- Styling:
  - Tailwind utilities via `public/explore/tw.css`.
  - Lighter cards, compact description text, subtle shadows; dark‑mode aware.

## Publishing & Versions (important)
- MCP Registry is immutable per version — publishing the same version twice returns 400.
- mcp‑merchant (stdio + SSE):
  - Bump version in `package.json`, code constants, and `server.json`.
  - Publish to npm first (so the Registry can reference the new stdio package).
  - Then run `mcp-publisher publish server.json`.
- mcp‑registry (SSE‑only):
  - No npm package required. Bump `server.json` (and the runtime VERSION for accuracy) and publish via `mcp-publisher`.
- Login for publishing (DNS):
  - `mcp-publisher login dns --domain shawndurrani.ai --private-key "$(cat mcp-merchant/mcp-dns-key.hex)"`

## Status field from Registry
- The public Registry may return `status: null` for entries (displayed as “unknown”). This is a registry metadata value, not runtime health. The Explorer can optionally probe SSE endpoints to infer “active”.
- To display Active in listings, set `"status": "active"` in `server.json` before publishing.
