[{"data":1,"prerenderedAt":332},["ShallowReactive",2],{"NoscriptNav_XrRK2e2e8meJ0jKVGkb5ULGQDVi3UiFQ9nupAr7Yns":3,"\u002Ftools\u002Fbrief":8},["Island",4],{"key":5,"result":6},"NoscriptNav_XrRK2e2e8meJ0jKVGkb5ULGQDVi3UiFQ9nupAr7Yns",{"head":7},{},{"id":9,"title":10,"authors":11,"body":13,"canonicalUrl":318,"canonicalWebsiteName":319,"category":320,"date":321,"description":322,"extension":323,"featured":324,"fullWidthLayout":324,"image":325,"imageAlt":325,"location":325,"meta":326,"metaImage":325,"navigation":327,"path":328,"seo":329,"stem":330,"venue":325,"venueUrl":325,"__hash__":331},"tools\u002Ftools\u002Fbrief.md","brief",[12],"andrew",{"type":14,"value":15,"toc":316},"minimark",[16,20,40,49,68,148,151,159,178,197,224,246,257,263,269,292,299,312],[17,18,19],"p",{},"Anyone landing in an unfamiliar repo, whether that's a new contributor, a security scanner, or an AI coding agent, has to answer the same handful of questions before doing anything useful: what language is this, how do I install dependencies, what's the test command, which linter do I run before committing, and for a security review, which functions in this stack are the dangerous ones.",[17,21,22,23,27,28,31,32,35,36,39],{},"The agent case just makes the cost of getting it wrong easiest to watch, because you can see Claude grep for ",[24,25,26],"code",{},"package.json",", read the Gemfile, try ",[24,29,30],{},"npm test",", get told there's no test script, try ",[24,33,34],{},"yarn test",", discover it's actually ",[24,37,38],{},"pnpm",", and only then get to the work you asked for. The answers are identical for every Rails project or every Go module that has ever existed, and rediscovering them from scratch every time is wasted effort.",[17,41,42,48],{},[43,44,10],"a",{"href":45,"rel":46},"https:\u002F\u002Fgithub.com\u002Fgit-pkgs\u002Fbrief",[47],"nofollow"," is a knowledge base of 516 tools across 54 language ecosystems, with a single Go binary in front of it that does the lookup and prints JSON when piped or a human summary on a TTY. The dataset is the part that doesn't exist anywhere else: invocation commands, config-file locations, and taxonomy for five hundred tools under one machine-readable schema. CI templates, devcontainer generators, and editor onboarding flows were the closest I found, each carrying a slice of it with no shared upstream. I think of the CLI as one view onto that data and expect there to be others.",[17,50,51,52,55,56,59,60,63,64,67],{},"Point it at a directory, a git URL, or a registry coordinate like ",[24,53,54],{},"gem:rails"," or ",[24,57,58],{},"npm:express"," and it reports the toolchain across twenty categories, each with the command to run and the config files that drive it, plus whatever governance and community files (license with SPDX identifier, security policy, ",[24,61,62],{},"CODEOWNERS",", ",[24,65,66],{},"FUNDING.yml",", and so on) it finds in the usual places.",[69,70,75],"pre",{"className":71,"code":72,"language":73,"meta":74,"style":74},"language-bash shiki shiki-themes github-light github-dark","brief .                       # local directory\nbrief gem:rails               # registry package, resolved to source repo\nbrief diff                    # only tools touched by changed files\nbrief missing                 # baseline categories with no tool configured\nbrief threat-model            # CWE\u002FOWASP categories implied by the stack\nbrief sinks                   # dangerous functions in detected tools\n","bash","",[24,76,77,93,104,115,126,137],{"__ignoreMap":74},[78,79,82,85,89],"span",{"class":80,"line":81},"line",1,[78,83,10],{"class":84},"sScJk",[78,86,88],{"class":87},"sZZnC"," .",[78,90,92],{"class":91},"sJ8bj","                       # local directory\n",[78,94,96,98,101],{"class":80,"line":95},2,[78,97,10],{"class":84},[78,99,100],{"class":87}," gem:rails",[78,102,103],{"class":91},"               # registry package, resolved to source repo\n",[78,105,107,109,112],{"class":80,"line":106},3,[78,108,10],{"class":84},[78,110,111],{"class":87}," diff",[78,113,114],{"class":91},"                    # only tools touched by changed files\n",[78,116,118,120,123],{"class":80,"line":117},4,[78,119,10],{"class":84},[78,121,122],{"class":87}," missing",[78,124,125],{"class":91},"                 # baseline categories with no tool configured\n",[78,127,129,131,134],{"class":80,"line":128},5,[78,130,10],{"class":84},[78,132,133],{"class":87}," threat-model",[78,135,136],{"class":91},"            # CWE\u002FOWASP categories implied by the stack\n",[78,138,140,142,145],{"class":80,"line":139},6,[78,141,10],{"class":84},[78,143,144],{"class":87}," sinks",[78,146,147],{"class":91},"                   # dangerous functions in detected tools\n",[17,149,150],{},"Checking all 516 definitions finishes in under 250ms, since anything that runs at the front of every session or pipeline step can't afford to be the slow part; on this blog's own repo it picks out Jekyll, Bundler, Rake, Dependabot and GitHub Actions in around 220ms, and on a Go project the output looks like:",[69,152,157],{"className":153,"code":155,"language":156},[154],"language-text","$ brief .\nLanguage:        Go\nPackage Manager: Go Modules (go mod download)\nTest:            go test (go test .\u002F...)\nLint:            golangci-lint (golangci-lint run)  [.golangci.yml]\nFormat:          gofmt (gofmt -w .)\nBuild:           GoReleaser (goreleaser release --clean)\nSecurity:        govulncheck (govulncheck .\u002F...)\nCI:              GitHub Actions  [.github\u002Fworkflows\u002F]\n","text",[24,158,155],{"__ignoreMap":74},[17,160,161,162,165,166,169,170,173,174,177],{},"I run it myself as the first thing after cloning anything, and I have it wired into my global agent instructions so every Claude session opens with ",[24,163,164],{},"brief ."," before anything else. That onboards the agent to the repo in one tool call and saves the tokens it would otherwise burn on exploratory greps and wrong guesses. On a feature branch ",[24,167,168],{},"brief diff"," narrows the report to just the tools touched by the changed files, so whoever is reading it knows to run ",[24,171,172],{},"golangci-lint"," because a ",[24,175,176],{},".go"," file changed without also being told about the Python linter in the monorepo's other half.",[17,179,180,181,186,187,190,191,196],{},"Because the JSON output follows a ",[43,182,185],{"href":183,"rel":184},"https:\u002F\u002Fgithub.com\u002Fgit-pkgs\u002Fbrief#library-usage",[47],"published schema",", it also works as a building block for other tooling: ",[24,188,189],{},"brief --json . | jq -r '.tools.test[0].command.run'"," gives a polyglot CI job the project's test command without anyone writing per-language cases, that lookup can drive a devcontainer or onboarding script, and the plan is to run it across every repo ",[43,192,195],{"href":193,"rel":194},"https:\u002F\u002Fecosyste.ms",[47],"ecosyste.ms"," indexes so that stack metadata is available for every package.",[17,198,199,200,203,204,209,210,214,215,219,220,223],{},"The detection rules are TOML rather than Go, which means adding a tool is a single file under ",[24,201,202],{},"knowledge\u002F"," with no code changes: a name, a category, the files or dependency names that signal its presence, the command to run it, and optionally a set of ",[43,205,208],{"href":206,"rel":207},"https:\u002F\u002Fgithub.com\u002Fecosyste-ms\u002Foss-taxonomy",[47],"oss-taxonomy"," tags describing what kind of thing it is. That taxonomy is ",[43,211,213],{"href":212},"\u002Ftools\u002Foss-taxonomy","a sibling project",": it builds the vocabulary for what a tool ",[216,217,218],"em",{},"is","; brief detects which tools a project ",[216,221,222],{},"uses",".",[17,225,226,227,232,233,236,237,63,239,63,242,245],{},"The dependency-name matching is driven by the same manifest parser as ",[43,228,231],{"href":229,"rel":230},"https:\u002F\u002Fgithub.com\u002Fgit-pkgs\u002Fgit-pkgs",[47],"git-pkgs",", so a tool definition can say \"present if ",[24,234,235],{},"rspec-core"," is in the bundle\" and brief already knows how to read Gemfiles, ",[24,238,26],{},[24,240,241],{},"go.mod",[24,243,244],{},"Cargo.toml",", and the other supported lockfile formats without any of that being reimplemented.",[17,247,248,249,252,253,256],{},"Those tags were originally there so the JSON output could say \"web framework\" rather than just \"build tool\", but once a few hundred definitions carried them they mapped cleanly onto CWE and OWASP categories, and ",[24,250,251],{},"brief threat-model"," on a Rails project produces SQL injection, mass assignment, XSS, CSRF, and SSTI without scanning a line of code, because that's what Rails and ActiveRecord are ",[216,254,255],{},"for",". The definitions also carry the specific dangerous functions each tool exposes, around 700 across the dataset, which is a reasonable starting grep list for a security review of a stack you've never worked in:",[69,258,261],{"className":259,"code":260,"language":156},[154],"$ brief sinks .\nActiveRecord:\n  Arel.sql            sql_injection      CWE-89\n  find_by_sql         sql_injection      CWE-89\n  where               sql_injection      CWE-89   string interpolation only\nRails:\n  html_safe           xss                CWE-79\n  redirect_to         open_redirect      CWE-601  when target is from params\n  render inline:      ssti               CWE-1336\nRuby:\n  eval                code_injection     CWE-95\n  Marshal.load        deserialization    CWE-502\n",[24,262,260],{"__ignoreMap":74},[17,264,265,268],{},[24,266,267],{},"brief missing"," inverts the check and reports which of five baseline categories (test, lint, format, typecheck, docs) have no tool configured for the detected ecosystems, naming the canonical choice for each gap. The detection engine is also importable as a Go library if you'd rather not shell out.",[17,270,271,272,280,281,286,287,223],{},"Tool definitions live in ",[43,273,276,277,279],{"href":274,"rel":275},"https:\u002F\u002Fgithub.com\u002Fgit-pkgs\u002Fbrief\u002Ftree\u002Fmain\u002Fknowledge",[47],"the ",[24,278,202],{}," directory"," and PRs adding new ones are the contributions I'm most interested in, particularly for ecosystems I don't write every day. If you point it at a project and it gets something wrong, ",[43,282,285],{"href":283,"rel":284},"https:\u002F\u002Fgithub.com\u002Fgit-pkgs\u002Fbrief\u002Fissues",[47],"open an issue"," or find me on ",[43,288,291],{"href":289,"rel":290},"https:\u002F\u002Fmastodon.social\u002F@andrewnez",[47],"Mastodon",[17,293,294,295,298],{},"You can ",[24,296,297],{},"brew install git-pkgs\u002Fgit-pkgs\u002Fbrief",", or see more instructions in the repository:",[300,301,304,305],"div",{"className":302},[303],"page-items","\n    ",[43,306,311],{"className":307,"href":45,"target":310},[308,309],"button","button--arrow","_blank","\n        Go to repository\n    ",[313,314,315],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":74,"searchDepth":95,"depth":95,"links":317},[],"https:\u002F\u002Fnesbitt.io\u002F2026\u002F04\u002F21\u002Fbrief.md","nesbitt.io","tooling","2026-04-21","A knowledge base of project conventions, exposed as a CLI.","md",false,null,{},true,"\u002Ftools\u002Fbrief",{"title":10,"description":322},"tools\u002Fbrief","l6BLSLTMBWg342soAlZZ-mJKm25bpFOEk8lKWZRS_-w",1780596103485]