Skip to content

feat: status --json + read-only MCP server; harden CI, release and repo hygiene - #66

Open
Bharath-code wants to merge 2 commits into
mainfrom
chore/oss-hygiene
Open

Bharath-code wants to merge 2 commits into
mainfrom
chore/oss-hygiene

Conversation

@Bharath-code

@Bharath-code Bharath-code commented Oct 17, 2026 •

Copy link
Copy Markdown
Owner

Description

Two commits:

  1. feat: status --json + read-only MCP server for AI agents. This is the first step in repositioning git-scope as the repo-state layer for people running many coding agents across repos and worktrees.

    • git-scope status --json prints every repo, most urgent first: path, branch, dirty count, ahead/behind, unpushed commits, last commit time, attention tier (ACTION/WATCH/CLEAN) and a reason.
    • git-scope mcp is a stdio MCP server built on the official modelcontextprotocol/go-sdk v1.8.0. Its tools are list_repos, needs_attention and repo_status(path), all read-only and all using the same scan → report code as the JSON command. repo_status only answers for repos under the configured roots.
    • Scanner correctness fixes found while probing edge cases:
      • linked worktrees were skipped entirely, because their .git is a file
      • commits on a never-pushed branch or a detached HEAD showed as CLEAN
      • merge conflicts counted as a clean tree
      • git calls had no timeout
    • README section added: "Use with Claude Code / Cursor".
  2. chore: CI, release supply chain and repo hygiene.

    • CI:
      • every action pinned to a commit SHA, including pages.yml
      • tests run on a Linux/macOS/Windows matrix
      • new go mod tidy -diff check
      • checkout no longer persists credentials
    • New .golangci.yml adds gosec, errorlint, revive, misspell and nolintlint.
    • Security fix from gosec: config, cache and nudge files are now created owner-only (0700/0600). The cache lists every scanned repo path.
    • GoReleaser:
      • brews → homebrew_casks and format → formats; goreleaser check was failing on these deprecations
      • SPDX SBOMs and signed build provenance (actions/attest-build-provenance)
      • the release step no longer runs go mod tidy
    • OpenSSF Scorecard workflow added; Pages write permissions scoped to the job.
    • Issue forms replace the markdown templates and blank issues are off, to help with the current spam.
    • SECURITY.md updated: supported version 1.4.x, private advisories, scope, release verification. CHANGELOG updated.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to change)
  • 📚 Documentation update
  • 🔧 Refactoring (no functional changes)

Checklist

  • I have tested my changes locally
  • I have updated the documentation (if applicable)
  • My code follows the project's style guidelines
  • I have added tests that prove my fix/feature works (if applicable)

Reviewer notes

  • Verified locally:
    • go test -race ./..., golangci-lint (0 issues), actionlint, goreleaser check
    • a goreleaser release --snapshot build: 6 archives plus a valid cask
    • git-scope status --json | jq, and a raw JSON-RPC stdio session calling all three MCP tools
  • Not verified yet: the macOS/Windows CI jobs (Windows may expose existing Unix-path assumptions in tests) and the release workflow itself.
  • Visible TUI change: never-pushed branches now show ↑N and rank as ACTION. On one real projects folder ACTION went from 2 repos to 6, all genuine.
  • Homebrew migration, after the first cask release: in homebrew-tap, add tap_migrations.json containing {"git-scope": "git-scope"} and delete Formula/git-scope.rb. The tap token also needs renewing.
  • Repo settings this PR depends on, not changed here: enable private vulnerability reporting, or the advisory links won't work. Also suggested: Dependabot alerts and a branch ruleset for main.
  • govulncheck may flag GO-2026-6617, a stdlib HTTP/2 issue, depending on the CI toolchain patch level. git-scope doesn't serve HTTP/2. If CI fails on it, bump the toolchain line in go.mod.

🤖 Generated with Claude Code


Kai context

Written by Kai from the change itself. Kai only edits this section; everything above it is the author's.

Adds git-scope status --json and a read-only git-scope mcp stdio server (built on modelcontextprotocol/go-sdk v1.8.0) with list_repos, needs_attention, and repo_status tools, all sharing a new internal/report package. Also fixes linked-worktree scanning, unpublished-commit detection, merge-conflict counting, and adds a 10s git-call timeout, plus CI/release hardening and repo-hygiene changes.

Changes

  • status --json command: cmd/git-scope/main.go wires a new status subcommand that scans configured roots and prints report.Build output as JSON via report.PrintJSON; --json is stripped from args by without.
  • MCP server: new internal/mcpserver/mcpserver.go registers three read-only tools (list_repos, needs_attention, repo_status) on a stdio transport; repo_status resolves paths canonically and only answers for repos under configured roots.
  • Report package: new internal/report/report.go defines Repo struct and Build (attention-sorted) / Reason / PrintJSON functions shared by both the CLI and MCP server.
  • Scanner fixes in internal/gitstatus/gitstatus.go: detects # branch.upstream to know when there is no upstream; adds unpublishedCommits using rev-list --count HEAD --not --remotes (skips repos with no remote); applyFileLine now counts u (unmerged/conflict) lines as unstaged; runGit wraps every call in a 10s context.WithTimeout.
  • Linked worktree scanning: internal/scan/scan.go matches .git files (not just directories) and returns nil instead of SkipDir for those files so nested repos are still found.
  • File permissions: internal/cache/cache.go, internal/config/config.go, and internal/nudge/nudge.go create directories with 0o700 and write files with 0o600.
  • CI workflows: .github/workflows/ci.yml splits into checks (format, tidy-diff, vet, govulncheck) and a test matrix (ubuntu/macOS/windows), pins all actions to SHAs, and sets persist-credentials: false; .github/workflows/pages.yml scopes pages/id-token write permissions to the deploy job and pins actions to SHAs.
  • Release workflow: .github/workflows/release.yml pins actions to SHAs, installs syft for SBOMs, runs actions/attest-build-provenance against dist/checksums.txt, and drops the go mod tidy pre-hook.
  • GoReleaser config (.goreleaser.yml): migrates brews → homebrew_casks (with quarantine-removal post-install hook), format → formats, and adds SPDX SBOM generation.
  • Lint config: new .golangci.yml enables gosec (excluding G204/G304), errorlint, revive, misspell, nolintlint, bodyclose, unconvert with test-path exclusions.
  • Scorecard: new .github/workflows/scorecard.yml runs OpenSSF Scorecard on schedule and push, uploading SARIF results.
  • Issue templates: markdown templates replaced by .yml forms (bug_report.yml, feature_request.yml) with config.yml disabling blank issues and linking to Discussions and security advisories.
  • Docs: README adds a "Use with Claude Code / Cursor" section; SECURITY.md updates supported version to 1.4.x, adds private-advisory reporting, scope, and release-verification instructions; CHANGELOG.md records all additions and fixes; .gitignore anchors binary names so cmd/git-scope/ is no longer ignored.

Testing

  • internal/report/report_test.go: verifies JSON shape and field values for clean, unpushed, stale-dirty, and scan-error repos; confirms attention sort order and that PrintJSON(nil) emits [].
  • internal/mcpserver/mcpserver_test.go: uses in-memory MCP transport to exercise all three tools — list_repos returns all repos, needs_attention drops clean repos, repo_status resolves a symlinked path with trailing slash, and rejects paths outside roots or empty paths.

Bharath-code and others added 2 commits October 16, 2026 00:28
- `git-scope status --json`: attention-sorted repo state (path, branch,
  dirty, ahead/behind, unpushed, last commit, tier, reason)
- `git-scope mcp`: stdio MCP server with list_repos, needs_attention and
  repo_status tools, sharing the same scan → report path
- scan linked worktrees (.git file), count conflicts as uncommitted,
  count unpublished commits on branches without upstream / detached HEAD
- bound every git call with a 10s timeout
- .gitignore: anchor binary names so cmd/git-scope/ is not ignored

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- CI: pin all actions to commit SHAs, test on Linux/macOS/Windows,
  check `go mod tidy -diff`, drop persisted checkout credentials
- Lint: add .golangci.yml (gosec, errorlint, revive, misspell, nolintlint)
- Security: create config/cache/nudge files owner-only (0700/0600)
- Release: migrate deprecated `brews` to `homebrew_casks` and
  `format` to `formats`; add SPDX SBOMs and signed build provenance;
  stop mutating go.mod at release time
- Add OpenSSF Scorecard workflow; scope Pages write permissions to the job
- Replace markdown issue templates with issue forms; disable blank issues
- SECURITY.md: current supported version, private advisory reporting,
  explicit scope and release verification
- CHANGELOG: record MCP/status work and the above

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kilo-code-bot

kilo-code-bot Bot commented Oct 17, 2026

Copy link
Copy Markdown

Kilo Code Review could not run — your account is out of credits.

Add credits or switch to a free model to enable reviews on this change.

@kaicontext kaicontext Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Kai review · 🔵 Your call, then merge (8/10)

Next: say yes or no to 2 decisions below, then merge when you're happy.

Size L · 1027 lines in 28 files · Risk L · decides on money, decides on access, changes CI or the build

To get to 10/10:

  • −2 · say yes or no to 2 decisions above
What Where
🤔 [money] The Homebrew cask drops com.apple.quarantine from an unnotarized binary, so macOS users installing via the cask after the next release run an unsigned binary with no Gatekeeper prompt — confirm that is the int… —
🤔 [access] SECURITY.md advertises private-advisory reporting links that 404 until private vulnerability reporting is enabled in repo settings — enable it before this reads as a promise to reporters. —

🐞 fix before merge · 🤔 correct as written, but someone should say yes.

What I made of it

Nothing I'd call a defect, but 2 decisions to say yes to.

0 confirmed findings, 11 refuted. Intent verified.

Important files changed
File Change
.github/ISSUE_TEMPLATE/bug_report.md modified · +0 −31
.github/ISSUE_TEMPLATE/bug_report.yml modified · +53 −0
.github/ISSUE_TEMPLATE/config.yml modified · +8 −0
.github/ISSUE_TEMPLATE/feature_request.md modified · +0 −20
.github/ISSUE_TEMPLATE/feature_request.yml modified · +30 −0
.github/workflows/ci.yml modified · +41 −11
.github/workflows/pages.yml modified · +10 −6
.github/workflows/release.yml modified · +19 −5

+21 more changed files in the full analysis.

What I opened — 28 files, 24 turns, 3m8s

6 of the 29 changed files don't appear below: .github/ISSUE_TEMPLATE/bug_report.md, .github/ISSUE_TEMPLATE/feature_request.md, go.sum, internal/cache/cache.go, internal/config/config.go, internal/nudge/nudge.go.

  • .github/ISSUE_TEMPLATE/bug_report.yml
  • .github/ISSUE_TEMPLATE/config.yml
  • .github/ISSUE_TEMPLATE/feature_request.yml
  • .github/workflows/ci.yml
  • .github/workflows/pages.yml
  • .github/workflows/release.yml
  • .github/workflows/scorecard.yml
  • .gitignore
  • .golangci.yml
  • .goreleaser.yml
  • CHANGELOG.md
  • README.md
  • SECURITY.md
  • cmd/git-scope/main.go
  • go.mod
  • internal/attention/attention.go
  • internal/attention/score.go
  • internal/gitops/gitops.go
  • internal/gitstatus/gitstatus.go
  • internal/gitstatus/gitstatus_test.go
  • internal/mcpserver/mcpserver.go
  • internal/mcpserver/mcpserver_test.go
  • internal/model/repo.go
  • internal/report/report.go
  • internal/report/report_test.go
  • internal/scan/scan.go
  • internal/scan/scan_test.go
  • internal/tui/actions.go
Full read-through

Scope

  • All Go source files in the diff: internal/mcpserver/mcpserver.go and test, internal/report/report.go and test, internal/gitstatus/gitstatus.go and test, internal/scan/scan.go and test, cmd/git-scope/main.go
  • Supporting callers: internal/attention/attention.go, internal/attention/score.go, internal/model/repo.go, internal/gitops/gitops.go, internal/tui/actions.go, internal/cache/cache.go, internal/config/config.go, internal/nudge/nudge.go
  • Workflow and config files: ci.yml, pages.yml, release.yml, scorecard.yml, .golangci.yml, .goreleaser.yml
  • Issue templates: bug_report.yml, feature_request.yml, config.yml, and deleted .md templates
  • Documentation: CHANGELOG.md, README.md, SECURITY.md, .gitignore, go.mod, go.sum
  • All Go source in the diff: cmd/git-scope/main.go, internal/mcpserver/mcpserver.go + test, internal/report/report.go + test, internal/gitstatus/gitstatus.go + test, internal/scan/scan.go + test, internal/attention/attention.go + score.go, internal/model/repo.go, internal/cache/cache.go, internal/config/config.go, internal/nudge/nudge.go, internal/gitops/gitops.go, internal/tui/actions.go
  • All workflow files: .github/workflows/ci.yml, pages.yml, release.yml, scorecard.yml
  • Config/build files: .golangci.yml, .goreleaser.yml, .gitignore, go.mod
  • Docs/templates: CHANGELOG.md, README.md, SECURITY.md, .github/ISSUE_TEMPLATE/*.yml + config.yml
  • All Go source files in the diff: internal/gitstatus/gitstatus.go, internal/scan/scan.go, internal/report/report.go, internal/mcpserver/mcpserver.go, cmd/git-scope/main.go, internal/attention/attention.go, internal/attention/score.go, internal/model/repo.go, internal/gitops/gitops.go, internal/tui/actions.go
  • All test files: internal/gitstatus/gitstatus_test.go, internal/scan/scan_test.go, internal/report/report_test.go, internal/mcpserver/mcpserver_test.go
  • All workflow files: ci.yml, pages.yml, release.yml, scorecard.yml
  • Config/tooling: .golangci.yml, .goreleaser.yml, .gitignore, go.mod, go.sum
  • Docs: README.md, SECURITY.md, CHANGELOG.md, issue templates (.yml/.md/config.yml)
  • Could not read github.com/modelcontextprotocol/go-sdk v1.8.0 source (external module not in tree) — SDK behavior rests on passing in-memory tests
  • Could not read GoReleaser's cask-generation contract — cask stanza correctness rests on author's goreleaser check

No proposed defect was confirmed by this check within the reviewed scope.

Limitations

  • Could not read github.com/modelcontextprotocol/go-sdk v1.8.0 source (fetched module not in tree): mcp.AddTool generic signature, mcp.Server.Run semantics for ctx propagation to tool handlers, ToolAnnotations fields, CallToolResult.StructuredContent/IsError — rest on the passing in-memory test, not on the SDK's type declarations
  • Could not read GoReleaser's cask-generation contract: whether a 'post' lifecycle hook stage exists for homebrew_casks, and whether the generated cask places the binary on PATH — rests on the author's 'goreleaser check' and snapshot build claims
  • Did not execute any code; all behavioral claims are from source reading alone
  • github.com/modelcontextprotocol/go-sdk v1.8.0 is a fetched module not present in this checkout; its AddTool generic signature, ToolAnnotations fields, and CallToolResult/IsError/StructuredContent semantics could not be read. The two MCP-related allegations rest on SDK behavior I could not verify from source.
  • GoReleaser's cask-generation contract is not in this tree; the homebrew_casks stanza's correctness rests on the author's goreleaser check and snapshot build, which I could not independently run.
  • No code was executed in this review; test-pass claims are taken from the author's notes and from reading the test assertions, not from running them.
  • MCP SDK (github.com/modelcontextprotocol/go-sdk v1.8.0) type signatures and semantics are unverified against the package's own source — AddTool generic return, ToolAnnotations/OpenWorldHint fields, CallToolResult.StructuredContent/IsError behavior rest on the passing in-memory test only
  • GoReleaser cask generation contract is unverified — whether the homebrew_casks stanza produces a working binary link cannot be confirmed from this tree

Decisions (need your call)

  • [money] The Homebrew cask drops com.apple.quarantine from an unnotarized binary, so macOS users installing via the cask after the next release run an unsigned binary with no Gatekeeper prompt — confirm that is the intended install posture, and that the generated cask stanza places the binary on PATH.
  • [access] SECURITY.md advertises private-advisory reporting links that 404 until private vulnerability reporting is enabled in repo settings — enable it before this reads as a promise to reporters.

+937 −110 · 29 files · reaches 12 · the full analysis
💬 Reply to any of my comments and I'll answer, or say @kaicontext anywhere on this PR — a question, or "take another look at the retry logic".

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant