Barrelman
May 29, 2026 · View on GitHub
Navigator-backed static linting and diagnostic packaging for the workspace toolchain. Barrelman ships the generic OpenAPI rule families (OAS structural parity, naming, documentation, structure, types, security, servers, paths, OWASP, references, syntax) and exposes a RulePack plug-in interface so downstream consumers can attach branded rule packs without forking.
Toolchain role
Barrelman sits one layer above navigator:
navigatorowns parsing, typed OpenAPI and Arazzo document models,$refindexes, workspace resolution primitives, and parse-time issues.barrelmanowns generic rule execution, rulesets, severities, filtering, diagnostic shaping, and the public plug-in surface.telescopeand other consumers run Barrelman to surface lint output in editors, CI, and reports. Branded rule packs (vendor-specific guideline families) live in downstream consumers and attach via the plug-in interface.
Barrelman does not own the parser or the canonical structural validator. The built-in oas3-schema rule maps Navigator issues into Barrelman diagnostics so downstream tools see one consistent structural-validation story. If Arazzo-specific lint rules are added, they should follow the same split: Navigator for document loading and schema correctness, Barrelman for static rule execution on top.
Core API
LintContent(uri, content, opts)runs all enabled rules against in-memory YAML/JSON.LintFiles(files, opts)runs the same rules against files on disk.Registry,Rule, andRuleMetalet you register custom rules.LintOptionscontrols severity filtering, rulesets, target version hints, and workspace settings.
If you call the root package directly and want a specific executable rule set, pass LintOptions.Rules explicitly or register rules into DefaultRegistry from the analyzers and checks packages before relying on built-in rulesets.
Navigator-owned structural and meta issues flow through Barrelman via the built-in oas3-schema rule. The rule ID is legacy OpenAPI-shaped for compatibility, but the diagnostics now describe the underlying document family through Navigator issue metadata so OpenAPI and Arazzo can share the same structural bridge.
Plug-in interface (barrelman.RulePack)
Downstream consumers attach extra rules at startup without forking Barrelman:
type RulePack interface {
Name() string
Register(reg *Registry)
}
func RegisterPlugin(p RulePack)
func ApplyPlugins(reg *Registry)
A consumer package registers its pack from init():
package mybrand
import "github.com/sailpoint-oss/barrelman"
type Pack struct{}
func (Pack) Name() string { return "mybrand" }
func (Pack) Register(reg *barrelman.Registry) { /* register rules */ }
func init() { barrelman.RegisterPlugin(Pack{}) }
Any binary that blank-imports mybrand and calls analyzers.RegisterAll(reg) picks up the pack automatically — RegisterAll calls ApplyPlugins after loading Barrelman's generic analyzers.
If you want a plug-in-free build, call analyzers.RegisterGeneric(reg) instead.
Exported helper functions
Downstream packs often need the same traversal helpers Barrelman uses internally:
analyzers.SchemaNameFromPointer— recover a schema name from a JSON-pointer-like path.analyzers.WalkAllSchemas— iterate every schema reachable from a document index.analyzers.HeaderDiagLoc— best diagnostic location for a header-related finding.
Config And Rulesets
Barrelman now owns the shared static-analysis config and ruleset contract.
- Canonical workspace config files are
.barrelman.yaml,.barrelman.yml,.barrelman/config.yaml, and.barrelman/config.yml. - Legacy
.telescope.yamland.telescope/config.yamlfiles are still discovered for compatibility. - Canonical built-in ruleset names are
barrelman:recommended,barrelman:all,barrelman:owasp, andbarrelman:strict. - Legacy
telescope:*ruleset aliases still resolve to the same built-in sets. - OpenAPI semantic rules remain OpenAPI-specific today; Arazzo support in Barrelman is currently the Navigator-backed structural/meta bridge plus any future Arazzo-specific rules layered on top.
Quick start
package main
import (
"fmt"
"log"
"github.com/sailpoint-oss/barrelman"
)
func main() {
content := []byte(`openapi: "3.1.0"
info:
title: Example
version: "1.0.0"
paths: {}`)
diags, err := barrelman.LintContent("file:///api.yaml", content, barrelman.LintOptions{})
if err != nil {
log.Fatal(err)
}
for _, d := range diags {
fmt.Printf("%s: %s\n", d.Code, d.Message)
}
}
Local sibling development
When changing Barrelman alongside other toolchain repos, prefer a workspace go.work file:
go work init .
go work use ../navigator ../telescope/server ../barometer
This keeps go.mod pins clean while you iterate on shared contracts.
Release coordination
.github/workflows/release.ymlcurrently auto-tags and publishes from pushes tomain.- If Barrelman changes diagnostic, ruleset, or config contracts, bump consumer integrations after
telescope/server. - Use
navigator/TOOLCHAIN_BOUNDARIES.mdfor the shared bump order andnavigator/TOOLCHAIN_FIXTURE_MATRIX.mdfor cross-repo smoke anchors. - A minimal local smoke pass is:
go test ./...cd ../telescope/server && go test ./...
Ownership boundaries
- Need CST or grammar work: use
tree-sitter-openapi. - Need parse/index/ref/model access: use
navigator. - Need rule execution or CI/editor diagnostics: use
barrelman. - Need LSP, code actions, or editor workflows: use
telescope. - Need vendor-branded guideline rules (e.g. an organisation-specific naming family): implement them in a downstream consumer and register via
barrelman.RegisterPlugin. They should NOT live in this repository.
See navigator/TOOLCHAIN_BOUNDARIES.md in the sibling workspace for the full cross-repo contract.
Related Repositories
This repo is part of a six-repo OpenAPI toolchain:
- tree-sitter-openapi — grammar and tree-sitter bindings
- navigator — parse, index,
$refresolution, document validation - cartographer — source-to-OpenAPI extractor for Go, Java, TypeScript, Python, C#
- telescope — VS Code extension, language server, and CLI built on the above
- barometer — live HTTP contract testing and Arazzo runner