<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Open Source on Brandon's Blog</title><link>http://blog.bmh.io/projects/</link><description>Recent content in Open Source on Brandon's Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Sun, 30 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="http://blog.bmh.io/projects/index.xml" rel="self" type="application/rss+xml"/><item><title>mcp-snapotter</title><link>http://blog.bmh.io/projects/mcp-snapotter/</link><pubDate>Sun, 30 Aug 2026 00:00:00 +0000</pubDate><guid>http://blog.bmh.io/projects/mcp-snapotter/</guid><description>&lt;p>&lt;a href="https://github.com/highb/mcp-snapotter">mcp-snapotter&lt;/a> is an
&lt;a href="https://modelcontextprotocol.io">MCP&lt;/a> server for
&lt;a href="https://github.com/snapotter-hq/SnapOtter">SnapOtter&lt;/a>, a self-hosted file-processing
platform. It exposes SnapOtter&amp;rsquo;s 243 tools to any MCP-compatible client
(&lt;a href="https://docs.anthropic.com/en/docs/claude-code">Claude Code&lt;/a>,
&lt;a href="https://claude.ai/download">Claude Desktop&lt;/a>, etc.) through a clean, discoverable
interface.&lt;/p>
&lt;p>Instead of flooding the model&amp;rsquo;s context with 243 near-identical tools, it exposes eight
generic ones and indexes the &lt;a href="https://www.openapis.org">OpenAPI&lt;/a> spec for discovery:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align: left">Tool&lt;/th>
&lt;th style="text-align: left">Purpose&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_list_tools&lt;/code>&lt;/td>
&lt;td style="text-align: left">Browse/search the catalog by section or keyword&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_describe_tool&lt;/code>&lt;/td>
&lt;td style="text-align: left">Show a tool&amp;rsquo;s documented settings fields&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_run_tool&lt;/code>&lt;/td>
&lt;td style="text-align: left">Run one tool on a file; awaits async jobs&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_run_pipeline&lt;/code>&lt;/td>
&lt;td style="text-align: left">Chain steps server-side in one pass&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_batch&lt;/code>&lt;/td>
&lt;td style="text-align: left">One tool over many files&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_upload_file&lt;/code>&lt;/td>
&lt;td style="text-align: left">Add a local file to the library&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_list_files&lt;/code>&lt;/td>
&lt;td style="text-align: left">List the SnapOtter library&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_get_file&lt;/code>&lt;/td>
&lt;td style="text-align: left">One file&amp;rsquo;s metadata and version history&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_download&lt;/code>&lt;/td>
&lt;td style="text-align: left">Fetch a downloadUrl to disk&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_health&lt;/code>&lt;/td>
&lt;td style="text-align: left">Connectivity check&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Settings are discovered at call time from SnapOtter&amp;rsquo;s validation errors, so the
server doesn&amp;rsquo;t need to model 243 settings schemas. Async tools (54 of them)
are handled transparently with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events">SSE&lt;/a>-based progress polling.&lt;/p></description><content>&lt;p>&lt;a href="https://github.com/highb/mcp-snapotter">mcp-snapotter&lt;/a> is an
&lt;a href="https://modelcontextprotocol.io">MCP&lt;/a> server for
&lt;a href="https://github.com/snapotter-hq/SnapOtter">SnapOtter&lt;/a>, a self-hosted file-processing
platform. It exposes SnapOtter&amp;rsquo;s 243 tools to any MCP-compatible client
(&lt;a href="https://docs.anthropic.com/en/docs/claude-code">Claude Code&lt;/a>,
&lt;a href="https://claude.ai/download">Claude Desktop&lt;/a>, etc.) through a clean, discoverable
interface.&lt;/p>
&lt;p>Instead of flooding the model&amp;rsquo;s context with 243 near-identical tools, it exposes eight
generic ones and indexes the &lt;a href="https://www.openapis.org">OpenAPI&lt;/a> spec for discovery:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align: left">Tool&lt;/th>
&lt;th style="text-align: left">Purpose&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_list_tools&lt;/code>&lt;/td>
&lt;td style="text-align: left">Browse/search the catalog by section or keyword&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_describe_tool&lt;/code>&lt;/td>
&lt;td style="text-align: left">Show a tool&amp;rsquo;s documented settings fields&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_run_tool&lt;/code>&lt;/td>
&lt;td style="text-align: left">Run one tool on a file; awaits async jobs&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_run_pipeline&lt;/code>&lt;/td>
&lt;td style="text-align: left">Chain steps server-side in one pass&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_batch&lt;/code>&lt;/td>
&lt;td style="text-align: left">One tool over many files&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_upload_file&lt;/code>&lt;/td>
&lt;td style="text-align: left">Add a local file to the library&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_list_files&lt;/code>&lt;/td>
&lt;td style="text-align: left">List the SnapOtter library&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_get_file&lt;/code>&lt;/td>
&lt;td style="text-align: left">One file&amp;rsquo;s metadata and version history&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_download&lt;/code>&lt;/td>
&lt;td style="text-align: left">Fetch a downloadUrl to disk&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;code>snapotter_health&lt;/code>&lt;/td>
&lt;td style="text-align: left">Connectivity check&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Settings are discovered at call time from SnapOtter&amp;rsquo;s validation errors, so the
server doesn&amp;rsquo;t need to model 243 settings schemas. Async tools (54 of them)
are handled transparently with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events">SSE&lt;/a>-based progress polling.&lt;/p>
&lt;p>Written in &lt;a href="https://python.org">Python&lt;/a> with strict &lt;a href="https://mypy-lang.org">mypy&lt;/a> and
&lt;a href="https://docs.astral.sh/ruff">ruff&lt;/a>, &lt;a href="https://opensource.org/licenses/MIT">MIT&lt;/a> licensed.&lt;/p>
&lt;p>Written with Claude / oh-my-pi running open models.&lt;/p></content></item><item><title>Tessera</title><link>http://blog.bmh.io/projects/tessera/</link><pubDate>Sat, 04 Jul 2026 00:00:00 +0000</pubDate><guid>http://blog.bmh.io/projects/tessera/</guid><description>&lt;p>&lt;a href="https://github.com/highb/museum-membership-finder">Tessera&lt;/a> answers: &lt;strong>given
where I live and the institutions I want access to, what is the cheapest legal
combination of museum memberships that covers them?&lt;/strong>&lt;/p>
&lt;p>Models the U.S. reciprocal-network landscape (NARM, ASTC, AHS, ROAM, MARP, ACM,
AZA, Time Travelers), encodes per-network/per-institution exclusion rules as
Datalog (&lt;a href="https://github.com/s-arash/ascent">Ascent&lt;/a>), and solves
membership-selection as weighted set-cover.&lt;/p>
&lt;p>All-&lt;a href="https://rust-lang.org">Rust&lt;/a> stack, only generated JavaScript:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://leptos.dev">Leptos&lt;/a> &lt;a href="https://webassembly.org">WASM&lt;/a> SPA for the web UI&lt;/li>
&lt;li>&lt;a href="https://github.com/s-arash/ascent">Ascent&lt;/a> &lt;a href="https://en.wikipedia.org/wiki/Datalog">Datalog&lt;/a> for rule encoding&lt;/li>
&lt;li>Pure-Rust optimizer, zero C/C++ FFI&lt;/li>
&lt;li>Local-first: user&amp;rsquo;s address never leaves the browser&lt;/li>
&lt;/ul>
&lt;p>Data is curated JSON with per-row provenance, shipped as &lt;a href="https://rkyv.org">rkyv&lt;/a> zero-copy
archives. Dual-licensed &lt;a href="https://opensource.org/licenses/MIT">MIT&lt;/a> /
&lt;a href="https://opensource.org/licenses/Apache-2.0">Apache 2.0&lt;/a>.&lt;/p></description><content>&lt;p>&lt;a href="https://github.com/highb/museum-membership-finder">Tessera&lt;/a> answers: &lt;strong>given
where I live and the institutions I want access to, what is the cheapest legal
combination of museum memberships that covers them?&lt;/strong>&lt;/p>
&lt;p>Models the U.S. reciprocal-network landscape (NARM, ASTC, AHS, ROAM, MARP, ACM,
AZA, Time Travelers), encodes per-network/per-institution exclusion rules as
Datalog (&lt;a href="https://github.com/s-arash/ascent">Ascent&lt;/a>), and solves
membership-selection as weighted set-cover.&lt;/p>
&lt;p>All-&lt;a href="https://rust-lang.org">Rust&lt;/a> stack, only generated JavaScript:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://leptos.dev">Leptos&lt;/a> &lt;a href="https://webassembly.org">WASM&lt;/a> SPA for the web UI&lt;/li>
&lt;li>&lt;a href="https://github.com/s-arash/ascent">Ascent&lt;/a> &lt;a href="https://en.wikipedia.org/wiki/Datalog">Datalog&lt;/a> for rule encoding&lt;/li>
&lt;li>Pure-Rust optimizer, zero C/C++ FFI&lt;/li>
&lt;li>Local-first: user&amp;rsquo;s address never leaves the browser&lt;/li>
&lt;/ul>
&lt;p>Data is curated JSON with per-row provenance, shipped as &lt;a href="https://rkyv.org">rkyv&lt;/a> zero-copy
archives. Dual-licensed &lt;a href="https://opensource.org/licenses/MIT">MIT&lt;/a> /
&lt;a href="https://opensource.org/licenses/Apache-2.0">Apache 2.0&lt;/a>.&lt;/p>
&lt;p>Written with Claude / oh-my-pi running open models.&lt;/p></content></item><item><title>namor</title><link>http://blog.bmh.io/projects/namor/</link><pubDate>Wed, 28 Jan 2026 00:00:00 +0000</pubDate><guid>http://blog.bmh.io/projects/namor/</guid><description>&lt;p>&lt;a href="https://github.com/highb/namor">Namor&lt;/a> is a pronounceable-name generator that
uses &lt;strong>corpus-based phonotactics&lt;/strong> rather than random letters. Instead of
producing gibberish like &amp;ldquo;xqztl,&amp;rdquo; it learns which sound combinations are
plausible by analyzing real name patterns.&lt;/p>
&lt;p>How it works:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Syllabification&lt;/strong> — breaks training names into onset, nucleus, and coda&lt;/li>
&lt;li>&lt;strong>Frequency extraction&lt;/strong> — counts how often each pattern appears in real names&lt;/li>
&lt;li>&lt;strong>Weighted sampling&lt;/strong> — generates new names by probabilistically combining patterns&lt;/li>
&lt;/ol>
&lt;p>Trained on 43 language corpora plus 26 mythological name sets. Ships as a
&lt;a href="https://highb.github.io/namor/">Vite SPA&lt;/a> with a
&lt;a href="https://highb.github.io/namor/standalone.html">standalone HTML build&lt;/a> (~11KB,
zero dependencies) that pre-computes frequency tables at build time. All
computation happens in the browser — no server, no API calls.&lt;/p></description><content>&lt;p>&lt;a href="https://github.com/highb/namor">Namor&lt;/a> is a pronounceable-name generator that
uses &lt;strong>corpus-based phonotactics&lt;/strong> rather than random letters. Instead of
producing gibberish like &amp;ldquo;xqztl,&amp;rdquo; it learns which sound combinations are
plausible by analyzing real name patterns.&lt;/p>
&lt;p>How it works:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Syllabification&lt;/strong> — breaks training names into onset, nucleus, and coda&lt;/li>
&lt;li>&lt;strong>Frequency extraction&lt;/strong> — counts how often each pattern appears in real names&lt;/li>
&lt;li>&lt;strong>Weighted sampling&lt;/strong> — generates new names by probabilistically combining patterns&lt;/li>
&lt;/ol>
&lt;p>Trained on 43 language corpora plus 26 mythological name sets. Ships as a
&lt;a href="https://highb.github.io/namor/">Vite SPA&lt;/a> with a
&lt;a href="https://highb.github.io/namor/standalone.html">standalone HTML build&lt;/a> (~11KB,
zero dependencies) that pre-computes frequency tables at build time. All
computation happens in the browser — no server, no API calls.&lt;/p>
&lt;p>&lt;a href="https://typescriptlang.org">TypeScript&lt;/a>, &lt;a href="https://vitejs.dev">Vite&lt;/a>, corpus data from
&lt;a href="https://github.com/MatthiasWinkelmann/firstname-database">MatthiasWinkelmann/firstname-database&lt;/a>.
&lt;a href="https://opensource.org/licenses/MIT">MIT&lt;/a> licensed.&lt;/p>
&lt;p>Written with Claude / oh-my-pi running open models.&lt;/p></content></item><item><title>asdf-teleport-ent</title><link>http://blog.bmh.io/projects/asdf-teleport-ent/</link><pubDate>Tue, 15 Mar 2022 00:00:00 +0000</pubDate><guid>http://blog.bmh.io/projects/asdf-teleport-ent/</guid><description>&lt;p>&lt;a href="https://github.com/highb/asdf-teleport-ent">asdf-teleport-ent&lt;/a> is an
&lt;a href="https://asdf-vm.com">asdf&lt;/a> and &lt;a href="https://mise.jdx.dev">mise&lt;/a> plugin for
managing &lt;a href="https://goteleport.com">Teleport Enterprise&lt;/a> CLI versions (&lt;code>tsh&lt;/code>, &lt;code>tctl&lt;/code>, &lt;code>teleport&lt;/code>).&lt;/p>
&lt;p>Built because I kept jumping between Teleport versions when testing upgrades and
didn&amp;rsquo;t want to manage symlinks by hand. Works with both asdf and mise:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># asdf&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>asdf plugin add teleport-ent
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>asdf install teleport-ent 14.2.2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>asdf set teleport-ent 14.2.2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># mise&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mise plugin install teleport-ent
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mise install teleport-ent@14.2.2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mise global teleport-ent@14.2.2
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Plain shell — depends on nothing but &lt;code>bash&lt;/code>, &lt;code>curl&lt;/code>, and &lt;code>tar&lt;/code>.
&lt;a href="https://opensource.org/licenses/Apache-2.0">Apache 2.0&lt;/a> licensed.&lt;/p></description><content>&lt;p>&lt;a href="https://github.com/highb/asdf-teleport-ent">asdf-teleport-ent&lt;/a> is an
&lt;a href="https://asdf-vm.com">asdf&lt;/a> and &lt;a href="https://mise.jdx.dev">mise&lt;/a> plugin for
managing &lt;a href="https://goteleport.com">Teleport Enterprise&lt;/a> CLI versions (&lt;code>tsh&lt;/code>, &lt;code>tctl&lt;/code>, &lt;code>teleport&lt;/code>).&lt;/p>
&lt;p>Built because I kept jumping between Teleport versions when testing upgrades and
didn&amp;rsquo;t want to manage symlinks by hand. Works with both asdf and mise:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># asdf&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>asdf plugin add teleport-ent
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>asdf install teleport-ent 14.2.2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>asdf set teleport-ent 14.2.2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># mise&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mise plugin install teleport-ent
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mise install teleport-ent@14.2.2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mise global teleport-ent@14.2.2
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Plain shell — depends on nothing but &lt;code>bash&lt;/code>, &lt;code>curl&lt;/code>, and &lt;code>tar&lt;/code>.
&lt;a href="https://opensource.org/licenses/Apache-2.0">Apache 2.0&lt;/a> licensed.&lt;/p></content></item><item><title>wordle-goggles</title><link>http://blog.bmh.io/projects/wordle-goggles/</link><pubDate>Thu, 27 Jan 2022 00:00:00 +0000</pubDate><guid>http://blog.bmh.io/projects/wordle-goggles/</guid><description>&lt;p>&lt;a href="https://github.com/highb/wordle-goggles">Wordle Goggles&lt;/a> is a Wordle analyzer
and solver that uses &lt;strong>NLTK corpus data&lt;/strong> to filter out uncommon words from
candidate lists. When Wordle was at peak hype in early 2022, this tool provided
data-driven guesses instead of relying on human word-frequency intuition.&lt;/p>
&lt;p>Uses the Reuters corpus via NLTK to score words by real-world usage frequency,
narrowing the solution space faster than random guessing. Written as a
single-file Python script — run it, feed in your Wordle results, and get the
next best guess.&lt;/p></description><content>&lt;p>&lt;a href="https://github.com/highb/wordle-goggles">Wordle Goggles&lt;/a> is a Wordle analyzer
and solver that uses &lt;strong>NLTK corpus data&lt;/strong> to filter out uncommon words from
candidate lists. When Wordle was at peak hype in early 2022, this tool provided
data-driven guesses instead of relying on human word-frequency intuition.&lt;/p>
&lt;p>Uses the Reuters corpus via NLTK to score words by real-world usage frequency,
narrowing the solution space faster than random guessing. Written as a
single-file Python script — run it, feed in your Wordle results, and get the
next best guess.&lt;/p>
&lt;p>&lt;a href="https://python.org">Python&lt;/a>, &lt;a href="https://nltk.org">NLTK&lt;/a>.
&lt;a href="https://opensource.org/licenses/MIT">MIT&lt;/a> licensed.&lt;/p></content></item><item><title>pathspec-ruby</title><link>http://blog.bmh.io/projects/pathspec-ruby/</link><pubDate>Thu, 10 Jul 2014 00:00:00 +0000</pubDate><guid>http://blog.bmh.io/projects/pathspec-ruby/</guid><description>&lt;p>&lt;a href="https://github.com/highb/pathspec-ruby">pathspec-ruby&lt;/a> is a &lt;a href="https://ruby-lang.org">Ruby&lt;/a> gem that
matches &lt;code>.gitignore&lt;/code>-style path specifications. It follows the full
&lt;a href="https://git-scm.com/docs/gitignore">gitignore syntax&lt;/a> — negation patterns,
directory-only rules, glob wildcards, and precedence ordering.&lt;/p>
&lt;p>Ported from the Python &lt;a href="https://pypi.org/project/pathspec">pathspec&lt;/a> library, it
ships a CLI (&lt;code>pathspec-rb&lt;/code>) and a Ruby API:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="display:flex;">&lt;span>gitignore &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">PathSpec&lt;/span>&lt;span style="color:#f92672">.&lt;/span>from_filename(&lt;span style="color:#e6db74">&amp;#39;.gitignore&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>gitignore&lt;span style="color:#f92672">.&lt;/span>match &lt;span style="color:#e6db74">&amp;#39;coverage/index.html&amp;#39;&lt;/span> &lt;span style="color:#75715e"># =&amp;gt; true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>gitignore&lt;span style="color:#f92672">.&lt;/span>match &lt;span style="color:#e6db74">&amp;#39;important.txt&amp;#39;&lt;/span> &lt;span style="color:#75715e"># =&amp;gt; false (negated)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>gitignore&lt;span style="color:#f92672">.&lt;/span>match_tree &lt;span style="color:#e6db74">&amp;#39;/src/repo&amp;#39;&lt;/span> &lt;span style="color:#75715e"># returns matching file paths&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Published as the &lt;code>pathspec&lt;/code> gem on &lt;a href="https://rubygems.org/gems/pathspec">RubyGems&lt;/a>. Supports Ruby 3.2 through 4.0.
&lt;a href="https://opensource.org/licenses/Apache-2.0">Apache 2.0&lt;/a> licensed.&lt;/p></description><content>&lt;p>&lt;a href="https://github.com/highb/pathspec-ruby">pathspec-ruby&lt;/a> is a &lt;a href="https://ruby-lang.org">Ruby&lt;/a> gem that
matches &lt;code>.gitignore&lt;/code>-style path specifications. It follows the full
&lt;a href="https://git-scm.com/docs/gitignore">gitignore syntax&lt;/a> — negation patterns,
directory-only rules, glob wildcards, and precedence ordering.&lt;/p>
&lt;p>Ported from the Python &lt;a href="https://pypi.org/project/pathspec">pathspec&lt;/a> library, it
ships a CLI (&lt;code>pathspec-rb&lt;/code>) and a Ruby API:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="display:flex;">&lt;span>gitignore &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">PathSpec&lt;/span>&lt;span style="color:#f92672">.&lt;/span>from_filename(&lt;span style="color:#e6db74">&amp;#39;.gitignore&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>gitignore&lt;span style="color:#f92672">.&lt;/span>match &lt;span style="color:#e6db74">&amp;#39;coverage/index.html&amp;#39;&lt;/span> &lt;span style="color:#75715e"># =&amp;gt; true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>gitignore&lt;span style="color:#f92672">.&lt;/span>match &lt;span style="color:#e6db74">&amp;#39;important.txt&amp;#39;&lt;/span> &lt;span style="color:#75715e"># =&amp;gt; false (negated)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>gitignore&lt;span style="color:#f92672">.&lt;/span>match_tree &lt;span style="color:#e6db74">&amp;#39;/src/repo&amp;#39;&lt;/span> &lt;span style="color:#75715e"># returns matching file paths&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Published as the &lt;code>pathspec&lt;/code> gem on &lt;a href="https://rubygems.org/gems/pathspec">RubyGems&lt;/a>. Supports Ruby 3.2 through 4.0.
&lt;a href="https://opensource.org/licenses/Apache-2.0">Apache 2.0&lt;/a> licensed.&lt;/p></content></item></channel></rss>