| Task | Command |
|---|---|
| Build | npm run build (tsc → fix-imports.js → chmod) |
| Dev (watch) | npm run dev (tsx — ts-node cannot load under TS 7) |
| Unit tests | npm test · core only npm run test:core · AI npm run test:ai |
| E2E (mock) | npm run test:e2e · tools npm run test:e2e:tools |
| E2E (live API) | E2E_REAL_API=true npm run test:e2e:tools:real |
| Coverage | npm run test:coverage |
| Lint / format | npm run lint (Biome) · npm run format |
| Inspect MCP server | npm run inspect |
src/index.ts— entry; boots anMcpServer(@modelcontextprotocol/serverv2, 2026-07-28 spec) viaserveStdio, which negotiates the protocol revision per connection. Each tool is registered withregisterTool; all of them share onedispatchToolcarrying the shutdown gate, in-flight tracking and result formatting. WiresToolRegistry+ProjectManagementServicethroughsrc/container.ts(tsyringe DI).- Tool errors: an execution failure returns
{content, isError: true}so the model can see and recover from it. A JSON-RPC error is reserved for protocol faults (unknown tool). Note v2 validates arguments against the declaredinputSchemabefore the handler runs, soToolValidatornever sees a missing required field. src/domain/— types, zod schemas, errors. No logic.src/services/— business logic.ProjectManagementServiceorchestrates per-feature services;services/ai/holds AI SDK providers.src/infrastructure/—github/(Octokit GraphQL/REST),tools/(MCP tool defs + registry + validators), plus cache, persistence, resilience, events.src/env.ts+src/cli.ts— config. CLI flags override env vars.
- Required:
GITHUB_TOKEN,GITHUB_OWNER,GITHUB_REPO. - GitHub credential chain, first hit wins:
--tokenCLI flag →$SECRETS_DIR/GITHUB_TOKENfile →GITHUB_TOKENenv →gh auth token. Theghfallback means a developer with a workingghlogin needs no configuration at all; disable it withGH_CLI_TOKEN_FALLBACK=false(it is also off automatically underNODE_ENV=test, so tests never shell out). - GitHub App installation auth (optional, outranks the PAT when all three are
set):
GITHUB_APP_ID,GITHUB_APP_PRIVATE_KEY,GITHUB_APP_INSTALLATION_ID. A partial App config falls back to the PAT rather than failing, so a half-set environment cannot lock the server out. - Every credential read goes through
getSecret()/requireToken(). Do NOT readprocess.env.GITHUB_TOKENdirectly — that bypasses the whole chain, which is exactly howSECRETS_DIRand--tokenwere silently broken before. - AI (optional, unlocks AI tools):
ANTHROPIC_API_KEY,GOOGLE_API_KEY,OPENAI_API_KEY,PERPLEXITY_API_KEY; model overridesAI_MAIN_MODEL,AI_PRD_MODEL,AI_RESEARCH_MODEL,AI_FALLBACK_MODEL. - Optional:
SYNC_ENABLED,SYNC_TIMEOUT_MS,CACHE_DIRECTORY,WEBHOOK_SECRET,WEBHOOK_PORT,SSE_ENABLED. - Webhook security: signature validation fails closed. With no
WEBHOOK_SECRET, webhooks are rejected unlessWEBHOOK_ALLOW_UNSIGNED=true(trusted dev only). - Secrets: set
SECRETS_DIR(e.g./run/secrets) to load any config/secret from a file named after it (Docker/k8s secret convention), checked before env vars.getSecret(name)inenv.tsreads fresh (rotation-aware). Vault/AWS SM are an extension point viaSecretProvider(src/infrastructure/secrets/). - Startup validation runs against the resolved config, not raw
process.env— validating the environment directly meant a token supplied by file or CLI flag failed the required-field check and the process exited before the resolver ran. - Logs are redacted:
redactSecrets()ininfrastructure/loggerstrips token/secret/password/apiKey/authorization-shaped keys from anything the logger stringifies, andGitHubConfig.tokenis non-enumerable soJSON.stringifycannot emit the PAT.
- ESM extensions: source omits
.jsin imports;postbuildrunsscripts/fix-imports.jsto add them. Never ship rawtscoutput — alwaysnpm run build. zodis on v4 (^4.4.3), paired withai@^7 /@ai-sdk/*@^4 (peer-accept^4.1.8) and@modelcontextprotocol/server@^2. Tool JSON Schema is generated by zod 4's nativez.toJSONSchema({io:'input'})inToolRegistry. Do NOT reintroducezod-to-json-schema: it does not support zod 4 and returns{type:'object'}with noproperties— silently, with no error — which left every tool advertising a parameterless schema. Guarded bysrc/__tests__/unit/infrastructure/tools/schema-generation.test.ts. zod-4 gotchas:z.recordneeds an explicit key schema (z.record(z.string(), v));ZodError.errors→.issues;.nonstrict()removed (objects strip by default).- Tests run on Vitest 4 (not Jest). Vitest rejects Jest-only CLI flags
outright —
--testPathPattern/--testPathIgnorePatternsexit withCACError: Unknown option, which silently broke 17 npm scripts. Filter by positional pattern (vitest run ai-services) and exclude with--exclude='**/tests/x/**'. - Test mocks must use
function, not an arrow, wherever the code under test callsnew—mockImplementation(() => ({...}))fails with "is not a constructor". Likewise abeforeEach(() => x.mockReset())with an implicit return hands the mock back to Vitest, which treats a returned function as a teardown callback and calls it; always use a block body. - E2E tool tests mock GitHub by default;
E2E_REAL_API=truehits the live API and consumes rate limit. isolatedModulesis ON. Every file must transpile independently, so a type re-exported as a value is an error.tscelides those;tsx/esbuild/bundlers emit a real runtime import that then fails to resolve. Useexport type/import type— including for decorated constructor params, whose typesemitDecoratorMetadatareferences at runtime.- Agent token budgets are metered server-side:
AIServiceFactory.getModelwraps every model with middleware that accumulates provider-reported usage intoCorrelationContext's AsyncLocalStorage, anddispatchTooldebits the agent's budget once per tool call (never per AI call —AgentStoreis GitHub-backed and does unlocked read-modify-write). This covers only what the server spends; an agent's own runtime spend never reaches this process, sorecord_usageremains the channel for that. ai@7 reports usage asinputTokens: {total,...}/outputTokens: {total,...}— objects, not numbers. Reading them as numbers yieldsNaN.
AGENTS.mdandCLAUDE.mdare kept identical. Edit both together.
This project is indexed by GitNexus as mcp-github-project-manager (5963 symbols, 15715 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
Index stale? Run
node .gitnexus/run.cjs analyzefrom the project root — it auto-selects an available runner. No.gitnexus/run.cjsyet?npx gitnexus analyze(npm 11 crash →npm i -g gitnexus; #1939).
- MUST run impact analysis before editing any symbol. Before modifying a function, class, or method, run
impact({target: "symbolName", direction: "upstream"})and report the blast radius (direct callers, affected processes, risk level) to the user. - MUST run
detect_changes()before committing to verify your changes only affect expected symbols and execution flows. For regression review, compare against the default branch:detect_changes({scope: "compare", base_ref: "main"}). - MUST warn the user if impact analysis returns HIGH or CRITICAL risk before proceeding with edits.
- When exploring unfamiliar code, use
query({search_query: "concept"})to find execution flows instead of grepping. It returns process-grouped results ranked by relevance. - When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use
context({name: "symbolName"}). - For security review,
explain({target: "fileOrSymbol"})lists taint findings (source→sink flows; needsanalyze --pdg).
- NEVER edit a function, class, or method without first running
impacton it. - NEVER ignore HIGH or CRITICAL risk warnings from impact analysis.
- NEVER rename symbols with find-and-replace — use
renamewhich understands the call graph. - NEVER commit changes without running
detect_changes()to check affected scope.
| Resource | Use for |
|---|---|
gitnexus://repo/mcp-github-project-manager/context |
Codebase overview, check index freshness |
gitnexus://repo/mcp-github-project-manager/clusters |
All functional areas |
gitnexus://repo/mcp-github-project-manager/processes |
All execution flows |
gitnexus://repo/mcp-github-project-manager/process/{name} |
Step-by-step execution trace |
| Task | Read this skill file |
|---|---|
| Understand architecture / "How does X work?" | .claude/skills/gitnexus/gitnexus-exploring/SKILL.md |
| Blast radius / "What breaks if I change X?" | .claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md |
| Trace bugs / "Why is X failing?" | .claude/skills/gitnexus/gitnexus-debugging/SKILL.md |
| Rename / extract / split / refactor | .claude/skills/gitnexus/gitnexus-refactoring/SKILL.md |
| Tools, resources, schema reference | .claude/skills/gitnexus/gitnexus-guide/SKILL.md |
| Index, status, clean, wiki CLI commands | .claude/skills/gitnexus/gitnexus-cli/SKILL.md |
This project uses bd (beads) for issue tracking. Run bd prime to see full workflow context and commands.
bd ready # Find available work
bd show <id> # View issue details
bd update <id> --claim # Claim work
bd close <id> # Complete work- Use
bdfor ALL task tracking — do NOT use TodoWrite, TaskCreate, or markdown TODO lists - Run
bd primefor detailed command reference and session close protocol - Use
bd rememberfor persistent knowledge — do NOT use MEMORY.md files
Architecture in one line: issues live in a local Dolt DB; sync uses refs/dolt/data on your git remote; .beads/issues.jsonl is a passive export. See https://github.com/gastownhall/beads/blob/main/docs/SYNC_CONCEPTS.md for details and anti-patterns.
The managed Beads block is task-tracking guidance, not permission to override repository, user, or orchestrator instructions.
- Conservative (default): Use
bdfor task tracking. Do not run git commits, git pushes, or Dolt remote sync unless explicitly asked. At handoff, report changed files, validation, and suggested next commands. - Minimal: Keep tool instruction files as pointers to
bd prime; use the same conservative git policy unless active instructions say otherwise. - Team-maintainer: Only when the repository explicitly opts in, agents may close beads, run quality gates, commit, and push as part of session close. A current "do not commit" or "do not push" instruction still wins.
This protocol applies when ending a Beads implementation workflow. It is subordinate to explicit user, repository, and orchestrator instructions.
- File issues for remaining work - Create beads for anything that needs follow-up
- Run quality gates (if code changed) - Tests, linters, builds
- Update issue status - Close finished work, update in-progress items
- Handle git/sync by active profile:
# Conservative/minimal/default: report status and proposed commands; wait for approval. git status # Team-maintainer opt-in only, unless current instructions forbid it: git pull --rebase bd dolt push git push git status
- Hand off - Summarize changes, validation, issue status, and any blocked sync/commit/push step
Critical rules:
- Explicit user or orchestrator instructions override this Beads block.
- Do not commit or push without clear authority from the active profile or the current user request.
- If a required sync or push is blocked, stop and report the exact command and error.