GitHits companion for the backend - provides MCP server and command-line tools for code example search.
We strive to produce high quality code that can easily be maintained. Focus is on long term development speed, not on quick wins.
This document contains the most important instructions that need to be kept always in context.
- Use very concise output and neutral tone
- If unclear about anything or stuck, please stop and ask for clarification
- Always verify assumptions
- Don't jump into coding, plan and assess the impact first
- Read more detailed documentation when needed
- Remember your MCP tools and use them when needed
Philosophy: "Create architecture that is performant and easy to test"
- Focus on building structures that are performant and scalable
- Build architecture that is easy to test
- Isolate functionality into sensible small modules
- Follow single responsibility principle
- Prefer public helper modules to lots of private methods
- Use dependency injection for external services (REST client, etc.)
- Do not eagerly validate network/proxy/environment configuration while constructing command dependencies when the command has local-only or no-network paths. Defer validation until the first network operation and add regression tests for malformed env values on local paths.
- GitHits information tools advertise
readOnlyHint: true, including internal result storage, caching, preparation, and research-thread state. Keep this policy covered by catalog tests; assess any future user-facing write tool separately. - For MCP/agent-facing tools, avoid coupled optional flags and default-true booleans. Design schemas for real agent calls, including empty strings, empty arrays, and explicit
falsevalues. - For MCP tool discovery, treat the tool name plus the first description sentence as a standalone selection surface. A verified claude.ai deferred-tool catalog rendered at most 80 characters: a sentence longer than 79 characters appeared as its first 79 plus an ellipsis, while connector descriptions and MCP server instructions did not reach selection. Lead with the natural user question and the tool's distinct job, keep that sentence within 79 characters when it must render whole, and avoid internal periods (including abbreviations, version literals, and filenames) because the observed sentence boundary is otherwise ambiguous. Keep registry counts/lists, argument mechanics, and follow-up routing after it. Also keep the first 80 raw description characters useful for clients that expose a raw prefix. Do not rely on neighboring tools for context. Add first-sentence/first-80 contract tests and run descriptor-only agent evals for description changes.
- For GraphQL/API-backed tools, treat minimal data fetching as part of the tool contract. Before adding or changing selected fields, compare the query against every consumer (text, verbose, JSON, MCP, CLI, and internal callers), use conditional fields or separate queries for mode-specific data, and add tests that assert the wire variables/selections for compact and detailed modes.
See docs/guidelines/ARCHITECTURAL_GUIDELINES.md for detailed planning checklist and design principles.
Human-readable tool text is an optimized product surface, not raw field serialization. Before editing it, inspect real output and preserve existing strengths: lead with the outcome, group related evidence, remove repetition and scaffolding, and retain stable follow-up locators, actions, and trust facts. Wrap free prose to the caller's width, keep formatter-authored punctuation ASCII while preserving backend Unicode, and never make color carry meaning. When CLI and MCP need the same information, share one formatter per tool with color and width as inputs; keep JSON lossless for machines. A complete data dump is not good output merely because it is complete.
Philosophy: "If it is not tested, it is likely broken"
Critical Rules:
- Use
bun testfor running tests - Use
bun run smoke:mcpandbun run smoke:cliwhen changing MCP tools, CLI commands, shared formatters, auth/error envelopes, or MCP/CLI parity behavior. These are live-capable local suites, not the normal unit suite; they must pass unauthenticated by validating auth handling, and provide deeper coverage when authenticated. After building, also runbun run smoke:cli:builtandbun run smoke:mcp:builtwhen changing smoke launch behavior or CI product validation; these secret-free modes executedist/cli.jsunder Node. - Use
bun run agent:e2ewhen changing MCP instructions, tool descriptions, or agent-facing tool behavior. This is a human/agent-driven qualitative eval, not a deterministic CI gate. Pick targeted workloads fromeval/agentic/README.md; run both Claude and Codex for broad instruction changes when practical. Inspecttool-calls.jsonandfinal.jsonfor actual tool use and the neutral answer/confidence,metrics.jsonfor derived token/cost/duration/tool-call metrics, andisolation-violations.jsonfor trace-validation failures, not just harness pass/fail. Treat usefulness or quality as reportable only when a later grading stage provides it. - Maintain smoke coverage when adding or changing user-facing tools/commands. Prefer structural UX assertions over brittle snapshots, and keep MCP
format: "json"and CLI--jsonbehavior aligned. - When changing GraphQL/API selections, add regression tests for over-fetch controls (for example
@includevariables, body omission, field lists, or query builders) and live-smoke the affected CLI/MCP surfaces when authenticated access is available. - Keep tests async and isolated
- Mock services at the interface level using factory functions
- Use mock factories from
test-helpers.ts(e.g.,createMockGitHitsService(),createMockAuthService()) - Test behavior, not implementation - focus on inputs and outputs
- Test only one layer at a time - mock dependencies
- When tests simulate another platform, simulate that platform's path semantics too. Use
path.win32for Windows paths and avoid mixed literals likeC:\\Users\\me/app; mixed separators can make tests pass while real Windows logic is broken.
Test Structure:
import { describe, expect, it, mock } from "bun:test";
import { createMockGitHitsService } from "./test-helpers.js";
describe("myTool", () => {
it("does something", async () => {
const mockService = createMockGitHitsService({
/* overrides */
});
// test...
});
});See docs/guidelines/TESTING.md for comprehensive patterns.
- Proposals -> Plans -> Implementation -> Completion
- Keep docs updated as features evolve:
- Implementation notes:
docs/implementation/ - Guidelines:
docs/guidelines/
- Implementation notes:
- Use test driven development whenever possible
- Document what and why with JSDoc comments
- Root
skills/andAGENTS.mdare the only authored shared agent guidance.CLAUDE.mdandGEMINI.mdmust remain symlinks toAGENTS.md. - Use the repository-internal
githits-plugin-maintenanceskill when changing skills, agent guidance, plugin/marketplace/extension manifests, MCP transport metadata, root release metadata, generator behavior, or agent-facing setup/auth behavior. It must remain under.agents/skills/and must not be published with the public rootskills/tree. - Do not edit generated plugin assets directly. Change their canonical inputs, run
bun run plugins:generate, inspect the diff, and runbun run plugins:check. packages/mcp/src/mcp/instructions.tsowns the stablebuildMcpQuickStart()guide. When it or the terminal guide section inskills/githits-mcp/SKILL.mdchanges, update both in the same PR;src/skills-packaging.test.tsexact-parity coverage is the contract.buildLocalMcpQuickStart()runtime appendices are excluded from the public skill copy. Behavior-dependent guide changes follow the public Agent Skill lifecycle.server.jsonowns the canonical plugin keyword list used by generated manifests; keeppackage.jsonaligned with it.- All plugin and extension packages use hosted remote MCP. Direct
githits initconfiguration retains local stdio except for Cursor, which is remote-only. Claude and Gemini direct setup remove legacy plugin or extension state before installing the user-scoped stdio server.
- Use
bun run devfor development - Use
bun testfor testing - Use
bun run buildbefore committing
- Always add TypeScript types for function parameters and returns
- Prefer interfaces to type aliases for object shapes
- Use
constassertions for literal types - Prefer explicit types over inference for public APIs
- Use Zod for runtime validation
- Dependency Injection: Use factory functions that accept dependencies
- Service Layer: Abstract external calls behind service interfaces
- Error Handling: Use
withErrorHandling()wrapper for consistent errors - Tool Pattern: Follow
ToolDefinitioninterface for MCP tools
- Root
src/**is still the publishedgithitsCLI implementation until the CLI package move completes. It owns Commander commands, local auth storage, browser login, init/setup flows, local stdio MCP startup, plugin/assistant packaging assets, and the diagnostics implementation/lifecycle (environment, process, and output destinations). packages/core-internalis private source. It owns transport-neutral service clients, service interfaces, shared request/header primitives, the host-suppliedServiceDiagnosticscontract, neutral service errors, PKCE helpers, andTokenProvider. It must not discover diagnostics environment settings or own diagnostics process/output destinations. Never publish or leak@githits/core-internalinto public artifacts.packages/mcpis the public@githits/mcppackage. Its public tool/server API ispackages/mcp/src/index.ts: transport-neutral MCP server creation, tool registration, descriptors, instructions, request-scoped service provider types, and MCP service types. Its public runtime/client API ispackages/mcp/src/client.ts, exported as@githits/mcp/client, for remote MCP servers that need concrete service implementations, token/header/config helpers, and optional injectedServiceDiagnostics.- The production hosted server at
https://mcp.githits.comlives in the separateremote-mcprepository and consumes the published@githits/mcppackage as the canonical implementation of tool registration, descriptors,quick_start, and tool logic.remote-mcpowns HTTP transport, request-scoped service composition, auth/session handling, deployment, and observability; do not duplicate package-owned MCP behavior there. A change in this repository reaches hosted clients only after@githits/mcpis released,remote-mcpupdates that dependency, and the hosted server is deployed. @githits/mcp/smoke-testis a public validation helper entrypoint for remote MCP servers. It exports smoke assertions andrunMcpSmoke()without depending on local CLI startup.@githits/mcp/internalis a workspace-only alias for root CLI transition helpers. External packages and theremote-mcprepository must never import it. If remote server work needs something internal, promote the smallest stable API through@githits/mcpinstead.- Public package artifacts for both root
githitsand@githits/mcpmust not contain@githits/core-internal,workspace:*,@githits/mcp/internal, or private source aliases in JS, declarations, or manifests. The public-package validator also rejects staticfs,node:fs,fs/promises, andnode:fs/promisesimports in core source and packed MCP artifacts, and rejects direct coreprocess.stderr/process.stdoutaccess. These checks cover statically resolved string-literal module edges; they do not claim browser compatibility.
- Every notable user-, agent-, operator-, or public-API-visible change must add
one independent
changes/<unique-name>.<category>.mdfragment with an explicit pending SemVer impact for every public artifact. Do not editCHANGELOG.mdoutside release preparation. Followdocs/implementation/release-process.mdandchanges/README.md. - Treat dated, versioned changelog sections as immutable historical records. Change them only to correct blatant, demonstrable factual errors, and keep any correction minimal.
githitsand@githits/mcphave separate release flows. They may be bumped together when both surfaces changed, but CLI-only changes should not bump@githits/mcp.- Root
githitsrelease versions must stay aligned with generated plugin/assistant manifests:.plugin/plugin.json,.claude-plugin/plugin.json,.codex-plugin/plugin.json,.cursor-plugin/plugin.json,.claude-plugin/marketplace.json,gemini-extension.json, and the portable/Antigravityplugin.json. The versionlessmcp_config.jsonmust also be regenerated and checked. @githits/mcprelease versions live inpackages/mcp/package.jsonand should change only for MCP package API, tool behavior, MCP instructions, schemas, MCP auth/error behavior, or remote-server-facing public type changes.- For coordinated CLI and MCP releases, keep the MCP minor aligned with the CLI minor for discoverability. The first MCP release for a CLI minor starts at
X.Y.0; later MCP-package-visible changes in that CLI minor bump the MCP patch. - A request to audit, prepare, create, cut, or release a version authorizes release preparation through opening the release PR only; it does not authorize merging, enabling auto-merge, tagging, or publishing. Merging requires separate, explicit human approval given after the release PR exists and identifying that PR. Earlier release requests do not count. Stop after opening the PR, report its URL and check status, and wait for that approval.
- Successful
Mainruns onmaintrigger both root and MCP release workflows. The MCP workflow publishes only when the package version is not already published; manual dispatch is for recovery or dry runs. - Release preparation consumes all fragments into separate versioned sections for each released artifact and deletes the consumed files.
- Validate package behavior from outside root path aliases. Repo-local imports can hide package export-map or declaration problems.
- Not mocking services in tests
- Missing error handling in async operations
- Not updating
index.tsexports when adding new modules
Use Conventional Commits format:
<type>: <description>
[optional body with context]
Types:
feat:- New featurefix:- Bug fixdocs:- Documentation onlyrefactor:- Code change that neither fixes a bug nor adds a featuretest:- Adding or updating testschore:- Maintenance tasks (deps, build, etc.)
Examples:
feat: add search MCP tool
Implements code example search via GitHits backend REST API
with license filtering support.
fix: handle expired tokens in auth status
- Use descriptive PR titles (they appear in release notes)
- Add labels for categorization:
feature/enhancement- New featuresbug/fix- Bug fixesdocumentation- Docs changesmaintenance/chore- Maintenanceskip-changelog- Exclude from release notes
- No single liners - include body with context
- Follow guidelines from
docs/guidelines/REVIEW_GUIDELINES.md - Do not amend commits or rebase unless asked specifically
src/
cli.ts # root CLI entry point for published githits package
container.ts # root CLI dependency injection
auth/ # OAuth PKCE utilities
commands/ # CLI commands and local stdio MCP command
services/ # CLI/local auth storage and service composition
tools/ # root CLI/MCP parity tests only
packages/
core-internal/ # private transport-neutral service/core source
mcp/ # public @githits/mcp package source
cli/ # private placeholder until CLI package move
docs/
guidelines/ # Development guidelines
implementation/ # Implementation documentation