npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

git-blinder

v0.1.0

Published

A local MCP gateway that gives each coding agent an enforced GitHub perimeter.

Readme

A racehorse wearing blinders leads a pack of horses without them

Prompts tell agents to stay in their lane. GitBlinder removes the other lanes.

GitBlinder keeps your GitHub token outside the agent and exposes a separate, enforced MCP perimeter for each responsibility. An agent connected to one perimeter receives only its allowed tools and path-filtered content. The repository and branch are fixed by the connection itself, not chosen by the agent or supplied in tool arguments.

Out-of-scope reads look absent. Out-of-scope writes never reach GitHub. Branch discovery and branch switching are kept outside the agent surface.

Why I built this

I started GitBlinder after launching a crowd of coding agents on a project built with spec-driven development (SDD).

At first, parallelism felt like a superpower. Then the repository and the agents' contexts grew:

  • agents became increasingly amnesiac as their context filled up;
  • they stepped on each other and overwrote work owned by another role;
  • implementation agents changed tests, or made them green without a real implementation behind them;
  • every new agent received far more repository context and GitHub authority than its task required.

The problem was not only prompting. Every agent could still see and touch everything. Their responsibilities were conventions, not boundaries.

GitBlinder applies the same idea as the single-responsibility principle to agent access: define one responsibility, carve out the smallest useful part of the repository, and bind one agent connection to it.

The agent becomes a narrow specialist. It cannot wander into another domain because that domain does not exist in its GitHub view.

The hypothesis

GitBlinder is an experiment in structurally focused agents. Enforced, disjoint perimeters should make it possible to:

| Goal | Mechanism | |---|---| | Preserve focus | Fix the repository and branch at connection time, then hide irrelevant files and tools | | Prevent collisions | Give concurrent agents non-overlapping write perimeters | | Protect test integrity | Let an implementer read tests without being able to rewrite them | | Build specialization | Keep one agent inside one stable domain of the codebase | | Reduce latency and cost | Return less repository data and spend fewer tokens rediscovering context |

These are hypotheses to measure, not benchmark claims. The companion gitblinder-sdd-lab provides a small, reproducible workload for comparing prompt-only roles with enforced ones.

Without GitBlinder every agent shares the full repository; with GitBlinder each agent is isolated to one folder

A concrete SDD workflow

Imagine one repository with a specification, its tests, and its implementation:

specs/**  ──►  test/**  ──►  src/**
   ▲              ▲             ▲
 reviewer      test author   implementer
 read-only     writes tests   writes source

The corresponding perimeters can be declared in YAML:

perimeters:
  spec-reviewer:
    repo: Math1987/gitblinder-sdd-lab
    tools: [get_tree, get_file, get_files, list_commits, get_commit]
    read:
      - "specs/**"
    write: []

  test-author:
    repo: Math1987/gitblinder-sdd-lab
    tools: [get_tree, get_file, get_files, push_files, list_commits, get_commit]
    read:
      - "specs/**"
      - "test/**"
      - "package.json"
    write:
      - "test/**"

  implementer:
    repo: Math1987/gitblinder-sdd-lab
    tools: [get_tree, get_file, get_files, push_files, list_commits, get_commit]
    read:
      - "specs/**"
      - "test/**"
      - "src/**"
      - "package.json"
    write:
      - "src/**"

At startup, each perimeter is bound to the repository's configured default branch (main when omitted). This creates three distinct MCP views:

http://127.0.0.1:7400/mcp/spec-reviewer
http://127.0.0.1:7400/mcp/test-author
http://127.0.0.1:7400/mcp/implementer

The test author cannot inspect the implementation. The implementer can read the fixed tests but cannot weaken them. With non-overlapping write globs, the two writing agents cannot overwrite one another. If an agent needs a feature branch, the operator allowlists it and the orchestrator connects the agent to /mcp/<perimeter>/<branch>.

How a perimeter works

GitHub token ─► GitBlinder
                  ├─ /mcp/spec-reviewer
                  │    └─ repo fixed · main fixed · specs/** read-only
                  ├─ /mcp/test-author/test-contract
                  │    └─ repo fixed · test-contract fixed · test/** writable
                  └─ /mcp/implementer/feature-parser
                       └─ repo fixed · feature-parser fixed · src/** writable
                                                        │
                                                        └─► GitHub

One local GitBlinder process owns the credential. Each named MCP endpoint is bound to one perimeter and revalidates every call before it reaches GitHub.

A perimeter controls:

  • repository — the agent cannot redirect a call to another repository;
  • bound branch — /mcp/<id> fixes the repository default branch, while /mcp/<id>/<branch> fixes an operator-allowlisted branch;
  • tools — tools outside its allowlist do not appear in tools/list;
  • read paths — trees, files, and results are filtered through read globs;
  • write paths — every path in a mutation must match write, or the entire mutation is rejected;
  • commit history — commit lists use prefixes derived from read, and commit details expose only readable files plus an opaque omitted count.

read and write are independent. Reading a file does not imply permission to change it, and writing a path does not automatically reveal its current contents.

Design principles

Absence for reads, explicit refusal for writes

An out-of-scope file or branch looks like it does not exist. This avoids turning the gateway into an oracle for hidden repository structure.

An out-of-scope write returns a clear error, so the agent does not continue under the false belief that a change succeeded.

All-or-nothing mutations

push_files creates an atomic multi-file commit. If one requested path falls outside the write perimeter, nothing is forwarded to GitHub.

One connection, one responsibility

An agent does not select or switch its repository, perimeter, or branch during a tool call. Its MCP URL establishes the binding, and GitBlinder removes the bound owner, repo, ref, and branch fields from the relevant agent tool schemas.

The operator owns branches

New perimeters allow only the repository's default branch. The operator may discover GitHub branches and add an existing branch to a perimeter. The agent never receives list_branches or compare, even if either tool is mistakenly included in the perimeter's tool grant.

Opaque history filtering

list_commits is restricted to static path prefixes derived from read globs. get_commit filters its changed files through the full read perimeter. A mixed commit reports omitted_count without naming hidden paths; a purely out-of-scope commit looks absent.

Explicit ownership

GitBlinder does not infer architecture or automatically resolve overlapping responsibilities. To isolate concurrent agents, define deliberate, non-overlapping write globs that follow the boundaries of your system.

Quick start

Requirements

  • Node.js 20 or newer
  • A GitHub personal access token

Use a dedicated, least-privilege token. The token remains the maximum authority of the GitBlinder process; perimeters can only narrow it.

Install from npm

Install the compiled CLI globally:

npm install --global git-blinder
git-blinder --version

Or try it without a global install:

npx --yes git-blinder@latest --help

Install from source

npm install
npm run build
npm link

Start the local gateway. The token stays in the operator process and is never passed to an agent:

export GITHUB_TOKEN=github_pat_xxxxx
git-blinder serve
Authenticated as your-github-user
git-blinder is running on http://127.0.0.1:7400

In another terminal, inspect what the token can access and create a perimeter:

# Operator commands authenticate with the same token as the local gateway.
export GITHUB_TOKEN=github_pat_xxxxx

git-blinder repos list
git-blinder branches list --repo YOUR_GITHUB_USER/YOUR_REPO

git-blinder perimeter create implementer \
  --repo YOUR_GITHUB_USER/YOUR_REPO \
  --read 'specs/**' \
  --write 'src/**' \
  --tools get_tree,get_file,get_files,push_files,list_commits,get_commit

git-blinder perimeter show implementer
git-blinder perimeter branch list implementer

A newly created perimeter permits only the repository's default branch. To use another branch, create it on GitHub first, then explicitly add it:

git-blinder perimeter branch add implementer feature-parser

The orchestrator chooses the branch by choosing the MCP URL:

| MCP URL | Bound branch | |---|---| | /mcp/implementer | Repository default branch | | /mcp/implementer/feature-parser | Allowlisted feature-parser branch |

Connect an agent to a scoped endpoint, never /mcp/root:

claude mcp add git-blinder-implementer \
  --transport streamable-http \
  http://127.0.0.1:7400/mcp/implementer/feature-parser

Cursor configuration:

{
  "mcpServers": {
    "git-blinder-implementer": {
      "url": "http://127.0.0.1:7400/mcp/implementer/feature-parser"
    }
  }
}

Ops note: unfiltered tools live at /mcp/root (not for agents). /mcp is health-only. /api/* requires Authorization: Bearer with the same token used for serve. Agents connect only to /mcp/<id> or /mcp/<id>/<branch>.

The operator can inspect the same filtered history without giving the agent a branch-discovery tool:

git-blinder perimeter commits list implementer --branch feature-parser
git-blinder perimeter commits show implementer COMMIT_SHA --branch feature-parser

git-blinder perimeter list
git-blinder perimeter delete implementer

To preload stable perimeters at startup, copy and edit the YAML example:

cp config.example.yaml config.yaml
GITHUB_TOKEN=github_pat_xxxxx git-blinder serve --config config.yaml

Runtime changes currently live in memory. Put long-lived perimeter definitions in YAML until registry persistence is implemented.

Tool surface

/mcp/root contains the complete operator/debug catalogue. A perimeter endpoint intersects its optional tool grant with the safe agent catalogue. POST /mcp does not expose tools (405).

| Tool | Ops /mcp/root | Perimeter endpoint | |---|---:|---:| | get_tree | yes | yes, path-filtered | | get_file | yes | yes, path-filtered | | get_files | yes | yes, path-filtered | | push_files | yes | yes, atomic and write-filtered | | list_commits | yes | yes, branch-bound and path-filtered | | get_commit | yes | yes, readable files only | | list_branches | yes | no | | compare | yes | no |

If tools is omitted from a perimeter, all safe perimeter tools are available. If it is present, only the granted safe tools appear in tools/list.

What works today

GitBlinder is an early alpha under active development. The current implementation includes:

  • local GitHub token validation and a streamable HTTP MCP server;
  • ops unfiltered MCP at /mcp/root ; health-only /mcp ; Bearer on /api/*;
  • YAML-preloaded and runtime-managed in-memory perimeters;
  • default-branch /mcp/<id> bindings and allowlisted /mcp/<id>/<branch> bindings;
  • forced repository and branch arguments, optional tool subsets, and path-scoped read / write;
  • strict path normalization and all-or-nothing writes via push_files;
  • operator CLI for repos/branches discovery and perimeter branch allowlists;
  • filtered commit history (list_commits via derived GitHub path= prefixes, get_commit with filtered files and omitted_count);
  • agent perimeter surface without list_branches / compare.

Current limitations worth knowing:

  • runtime perimeter and branch-allowlist changes are not persisted;
  • one process owns one GitHub token, and each perimeter targets one repository;
  • list_commits returns an empty list when no static prefix can be derived from a read glob such as ** or *.md;
  • /mcp/root remains available for operator/debug use (not for agents);
  • /api/* is protected by the ops Bearer token, but perimeter MCP URLs are still capability-by-path (guessable ids) in this version.

See SPEC.md for the model, CLI-SPEC.md for the CLI, and features/cli/ for executable contracts.

Security boundary

GitBlinder is a GitHub capability gateway, not an operating-system sandbox. Its guarantees assume that an agent:

  • reaches GitHub only through its scoped /mcp/<id>[/<branch>] endpoint;
  • cannot read the GitHub token from the environment or process;
  • does not also receive an unrestricted local clone, shell, or alternative GitHub credential that bypasses the gateway.

Bind the server to localhost, use a least-privilege upstream token, and give each agent only its named MCP endpoint.

Development

# Run from source
npx tsx src/cli/index.ts serve --config config.yaml

# Unit, integration, and E2E tests
npm test

# All supported behavioral contracts
npm run test:features

# Two remaining Git-write harness scenarios
npm run test:features:wip

# One feature file
npm run test:features -- features/cli/03_perimeter_mcp.feature

The test suite uses a deterministic mock GitHub upstream; no real repository is needed for perimeter and filtering tests. CLI and agent-perception contracts are wired and executable. Two scenarios remain explicitly tagged @wip while the mock Git write flow is completed: a successful bound-branch write and the cross-perimeter check after a concurrent write.

Documentation

License

MIT