Barn is the Git-backed Ferret Registry. Human-reviewed registration source
records live under registry/; Barn compiles them into a deterministic,
hierarchical public distribution stored on the CI-owned gh-pages branch.
Publishing a module or a version means merging a pull request that passes the
registry validation workflow. Barn does not discover releases by polling
source repositories.
registry/
modules/
<owner>/
<module>/
manifest.json
versions/
v<semver>.json
plugins/
gh-pages branch root
.nojekyll
CNAME
index.json
categories.json
categories/
<category>.json
modules/
index.json
<owner>/
<module>/
index.json
versions/
<version>/
api.json
index.json
docs.html
docs.md
plugins/
index.json
registry/ is Barn's reviewed source tree, not a separate registry product.
Module registrations live under registry/modules/. registry/plugins/ is
reserved until plugin registration contracts are defined. The ignored local
dist/ tree is disposable full-generation output; the same public hierarchy is
persisted at the root of gh-pages, which GitHub Pages serves directly.
Contributors must not create or edit generated artifacts. Consumers navigate
from index.json and do not need Barn's registry/ source tree or direct
access to registered Git repositories.
The root index records source.commit, the exact main revision from which
the published tree was generated. It intentionally does not contain the
gh-pages commit because that commit cannot refer to itself. The published
branch acts as the validated cache for immutable release artifacts; normal
Registry-only updates reuse unchanged version directories byte-for-byte and
regenerate only affected releases and cheap global projections.
categories.json is the lightweight category discovery index. It lists
each category's stable ID, generated display name, module count, and link to
the corresponding categories/<category>.json document; it does not
embed module membership. Each per-category document contains the category
identity and the same compact id, latest, and href module summaries used
by modules/index.json, so consumers can render a listing and follow a
module link for its full details.
Categories are explicit, flat metadata from the selected ferret.yaml: the
highest stable release, or the newest prerelease when a module has no stable
release. A module may declare more than one category and therefore appear in
multiple category indexes. Barn does not infer categories from FQL namespaces,
module names, source paths, or directory structure.
The canonical identity is the lowercase <owner>/<module> coordinate.
Registry manifests contain only that identity and an anonymous HTTPS Git
source. Barn rejects mixed-case identity values and directory segments before
Git inspection or distribution generation; it never silently lowercases stored
input. Generated module IDs are the exact <owner>/<module> value, while the
Ferret runtime namespace remains an independent, case-sensitive identifier.
Each version record names a Git tag and pins the exact commit to which the tag
must resolve. Package descriptive metadata comes from ferret.yaml at the
pinned commit and optional monorepo source path. The installable package path
comes from the adjacent go.mod module directive. Barn parses and validates
that directive against the published version; it never derives a package path
from the repository URL.
After an unstamped version record reaches main, Barn assigns publishedAt
once and commits it back to the canonical record. The value is a whole-second
UTC RFC3339 timestamp and is immutable after assignment. Generated module
documents propagate that stored value into each version summary; regeneration
never derives it again or consults Git history.
For every registered version, Barn also reads README.md from the module root
at the exact pinned commit. It publishes those bytes as version-scoped
docs.md and publishes a sanitized, browser-ready docs.html fragment with
stable heading anchors. Relative Markdown links are resolved against the
manifest's explicit documentation URL. Barn does not fetch that URL or try
alternative documentation filenames.
Barn also derives a version-scoped Ferret API Reference from the Go source at
that commit and publishes it as api.json. The artifact contains namespaces,
functions, fixed or variadic signatures, structured parameters, return values,
visible failures, deprecation metadata, and ordinary Go-doc prose. It is
registration-driven: Barn does not copy or validate the manifest's exports
list. Constants, types, properties, methods, queryable host values, and query
dialect strings remain in the hand-written documentation because the current
SDK has no explicit registration metadata for them. The pinned README.md,
docs.md, and docs.html remain required and separate from the generated API
Reference.
Named registered declarations may provide structured Ferret-facing metadata
using the canonical Ferret API Documentation v1
contract.
Barn normalizes Go line and block documentation, delegates the reusable grammar
and metadata validation to github.com/MontFerret/specs/pkg/api, and maps a
typed documentation error back to the declaration's exact source position.
Comments on declarations that are not part of the registered Ferret API are not
parsed.
Barn retains the source-specific rules around that portable contract. Without
structured parameters it emits name-only fallback objects from the analyzed Go
signature. An authored parameter list replaces that fallback and must match a
fixed Ferret arity; variadic registrations may describe multiple logical
Ferret parameters. Malformed registered documentation or an arity mismatch
fails analysis and publication preparation without a partial API artifact.
Documented parameter and return types flow directly into Specs' recursive
named, union, and list model. Barn never infers semantic types from Go
signatures, type assertions, or function bodies. Type metadata does not create
overloads: signature identity remains fixed arity or variadic registration.
Generated documents continue to use the closed API Reference v1 wire contract,
schemaVersion: 1, and its existing schema ID. The canonical model, strict JSON
parser, and same-document validator are provided by Specs pkg/api.
Barn consumes the Registry v1, Module Manifest v1, and generated Registry
artifact v1 contracts from github.com/MontFerret/specs.
Barn exposes two reusable packages for CLIs and other Go tooling:
github.com/MontFerret/barn/pkg/registryconsumes the generated static distribution. It discovers artifact links from the root index, so callers do not construct paths inside the published tree. Version records expose the validated package path asVersion.Package.Pathand absolute content artifact URLs; version summaries expose their immutablePublishedAttime. Wire parsing and same-document validation use the portable artifact contracts from specs; transport, same-origin navigation, and cross-document consistency remain client responsibilities.github.com/MontFerret/barn/pkg/publishvalidates a tagged module release and prepares the Barn source records for a Git pull request. It does not write the records, upload a package, or call a Git hosting API.
The Barn generator remains internal and is the only component that turns the
reviewed registry/ source tree into a local or gh-pages distribution.
Ferret specs remain the canonical owner of module manifests and Registry v1
source-record validation.
Create a registry client with the production host or an injected base URL and HTTP client:
client, err := registry.NewClient()
if err != nil {
return err
}
modules, err := client.Search(ctx, registry.SearchOptions{
Query: "openai",
Category: "ai",
})
if err != nil {
return err
}Search queries are case-insensitive substring matches against canonical module
IDs and descriptions. When Category is set, text matching is limited to the
modules in that category.
Prepare a release from the local module directory and an already-pushed tag:
result, err := publish.Prepare(ctx, publish.Request{
Directory: ".",
Tag: "v1.2.3",
})
if err != nil {
return err
}
// result.Files contains deterministic Barn-relative source records. The
// caller decides how to place them in a branch and submit a pull request.publish.Prepare loads ferret.yaml, consults the static registry to
distinguish a new module from a new version, resolves the tag through anonymous
HTTPS Git, validates the pinned manifest and documentation using the same Git
inspection and API-analysis path as Barn CI, and returns structured records
without modifying either repository. Source-analysis failures are exposed as
the public publish.StageAPI preparation stage.
Barn analyzes source without checking it out into a working repository and
without executing module code. It materializes the exact verified commit into
a temporary tree, rejects symlinks and other non-regular source-tree entries,
and rejects local replace directives that resolve outside that tree. It then
loads non-test packages rooted at the manifest source directory with Go AST
and type information.
Supported registration forms are intentionally explicit:
- an inline or statically named callback passed to
sdk.NewModule; - a returned local module type whose
Register(module.Bootstrap) errormethod performs registration, as used by the LLM module; - module-local helper calls across packages with statically propagated
LibraryandNamespace("...")values; sdk.RegisterFunctionswith directsdk.Funcvalues, static composite slices, and staticappendcomposition;sdk.Bindandsdk.Bind0throughsdk.Bind4;- direct
Function().A0()throughA4()andVar()builder chains withAdd; and - named functions, function literals, or factories whose return paths resolve to exactly one statically identifiable function target.
Configuration branches are analyzed as a union, so optional registrations and
legacy global registrations must all remain statically recognizable. Missing
or _ Go parameter names become stable arg1, arg2, and so on. Go-doc text
is included only when a registered value resolves unambiguously to a named Go
declaration.
Dynamic function or namespace names, loop or map-built definitions,
reflection, interface-dispatched or external registration helpers,
function-builder From or Remove, ambiguous factories, and dynamically
selected module roots are unsupported. Barn fails validation and publication
preparation instead of emitting a partial artifact.
Modules that register hooks or host values but no Ferret functions still emit
a valid API Reference with an empty namespaces array. Those non-function
surfaces remain documented only in the required hand-written documentation.
Analysis uses the fixed linux/amd64 platform with CGO disabled, the locally
selected Go toolchain, GOWORK=off, GOENV=off, read-only modules, build-VCS
metadata disabled, and only the public Go proxy and checksum database. VCS
dependency fallback is disabled. CI currently runs Go 1.26.x because that is
required by the published module set; Barn's reusable library module retains
its Go 1.25 minimum. A release must type-check under that analysis environment.
Ferret modules are published to Barn through pull requests. The Ferret CLI prepares the registry records for you and validates the release against its public source repository.
Before publishing, make sure your module: The standard module-author workflow is handled by the Ferret CLI while Barn retains pull-request review and CI validation:
git tag v1.0.0
git push origin v1.0.0
ferret mod publishferret mod publish validates the public tagged release through Barn's
pkg/publish preparation API, creates or reuses the author's personal Barn
fork, commits only the required Registry source records, and opens a pull
request against this repository. Authors do not need a local Barn checkout or
knowledge of the record layout below.
The CLI reads GH_TOKEN or GITHUB_TOKEN, then falls back to an authenticated
GitHub CLI session from gh auth token --hostname github.com. Use
ferret mod publish --dry-run for complete non-mutating release validation and
ferret mod publish --print to inspect the deterministic Barn-relative records
as JSON. Exact existing pull requests are returned on retry; published versions
are successful no-ops, and immutable records or divergent publication branches
are never overwritten.
The record-level process below remains available for recovery, external automation, and Registry operators. To submit records manually, fork this repository, create a branch containing only the required additions, and open a pull request.
- has a valid
ferret.yamlandgo.mod; - includes its release documentation in
README.md; - is committed to a public Git repository that supports anonymous HTTPS access; and
- has its release tag pushed to that repository.
From the module directory, run:
- the source repository is public and supports anonymous HTTPS Git access;
- the release tag and its target commit have been pushed to that repository;
- a valid
ferret.yamlexists at the repository root, or at the optional module source path in a monorepo; - a valid
go.modexists besideferret.yaml, and its module directive is compatible with the release version; - a
README.mdcontaining the release documentation exists beside thatferret.yaml; - the module's Ferret registrations use one of the statically supported API Reference authoring forms above;
- the manifest's
nameis the<owner>/<module>being registered and itsversionis the exact release version; and - the version record uses the full lowercase commit hash to which the tag
resolves. From a local clone of the source repository, obtain it with
git rev-parse 'v1.2.3^{commit}', replacingv1.2.3with the release tag.
ferret mod publishThe command validates the module and its release, resolves the pushed tag to its exact commit, checks the public Ferret registry, and prints the Barn records that need to be submitted.
By default, Ferret expects the release tag to be:
v<version>for a standalone module; or<module-directory>/v<version>for a module inside a monorepo.
For example:
v1.2.3
or:
modules/http/v1.2.3
If your repository uses a different tag, specify it explicitly:
ferret mod publish --tag <tag>Fork the Barn repository, create a branch, and add the records produced by ferret mod publish.
For a module's first release, the CLI produces both its module manifest and version record:
registry/modules/acme/http/
manifest.json
versions/
v1.2.3.json
For subsequent releases, only a new version record is required:
registry/modules/acme/http/versions/v1.3.0.json
Use the records exactly as produced by the CLI. Do not edit previously published module manifests or version records.
Do not add publishedAt yourself. Barn assigns the publication timestamp after a version first enters the registry, and contributor-supplied timestamps are rejected.
Before opening the pull request, run:
make checkCommit only the registration records. Do not create, edit, or commit anything under dist/, and do not add entries under registry/plugins/; plugin registration is not supported yet.
Barn CI validates the registration against the module's public source repository. It verifies the release tag and pinned commit, validates the module manifest and version, snapshots the release documentation, and generates the registry artifacts used by the public Ferret Registry.
Pull-request-generated artifacts are discarded.
After the pull request is merged, Barn assigns the release's publication
timestamp on main. The resulting fully stamped commit updates gh-pages by
enriching only affected releases, reusing existing immutable release files,
and rebuilding the inexpensive indexes. Published module sources, version
identities, assigned timestamps, and reused artifact bytes are immutable.
make check # Formatting, vet, tests, and registry validation.
make validate # Validate layout and pinned source releases.
make generate # Generate the complete public distribution.
make verify # Fail if any generated dist/ file differs.
make generate-pages OUTPUT=<path> PREVIOUS=<gh-pages-path>
make verify-pages OUTPUT=<path> SOURCE_COMMIT=<main-commit>
make check-immutable BASE=<git-object>
make stamp # Stamp canonical versions missing publishedAt.
make check-stamped # Check that every canonical version is stamped.make stamp STAMP_TIMESTAMP=<RFC3339> supplies a deterministic timestamp;
without it, Barn uses the current UTC time. The initial 17 registry versions
were backfilled with 2026-08-07T18:24:28Z, the committer time of the earliest
Git commit (96355d9) in which those versions were registered. That history
lookup was a one-time migration; ongoing generation relies only on the stored
timestamps.
The generation commands are maintainer and CI tools; module registrants do not
need to run them. The Barn CLI's --root option refers to the Barn repository
root containing registry/, not to the registry/ source directory. Without
an explicit --output, generated output is written to dist/ beneath that
root.
make generate and make verify always perform a full rebuild and remain the
recovery, migration, and debugging path. CI uses make generate-pages in
auto mode: a valid ancestor gh-pages tree plus Registry-only source changes
selects incremental generation; bootstrap, the legacy root format, or any
non-Registry change selects a full rebuild. Malformed or divergent cached state
fails closed and requires an explicit full rebuild.
Barn uses a dedicated GitHub App for the trusted canonical mutation that adds
publication timestamps after a registration pull request reaches main.
Maintainers must complete this setup before merging an unstamped publication:
- Create a GitHub App named
Ferret Barn Publisherwith only the repository permissionContents: Read and write. - Install the App only on
MontFerret/barn. - Store its App ID as the organization Actions secret
BARN_PUBLISHER_APP_ID, with access limited toMontFerret/barn. - Store its private key as the organization Actions secret
BARN_PUBLISHER_PRIVATE_KEY, with the same repository restriction. - Add
Ferret Barn Publisherto themainandgh-pagesbranch ruleset bypass lists withAlways allow; block contributor pushes, force pushes, and deletion ofgh-pages. - Release the provenance-aware Barn Registry client and upgrade maintained
strict consumers before changing the production root document. Older
artifact-v1 parsers reject the newly required
sourcefield. - Run the CI workflow once with
full_rebuildenabled to bootstrapgh-pages, then configure GitHub Pages to deploy fromgh-pagesat/while retainingregistry.ferretlang.organd HTTPS enforcement.
The stamping workflow keeps its default GITHUB_TOKEN read-only. It creates a
current-repository installation token only when stamping changed canonical
records or publishing a validated candidate, uses that token for direct pushes,
and does not fall back to another credential if token creation or a ruleset
bypass fails. Pull request CI does not reference or receive the Publisher
credentials. Never commit the App private key or a generated installation
token.
Automatic stamping runs only when a push to main changes a canonical module
version record under registry/modules/<owner>/<module>/versions/. Unrelated
pushes do not retry a failed publication; after correcting Publisher
configuration, use the workflow's manual dispatch to resume pending stamping.
Ferret Release Bot remains a separate release-oriented identity. Do not reuse
its App ID or private key, widen its permissions, or assign Barn publication
responsibilities to it.
Remote validation uses provider-independent Git operations. It permits only anonymous public HTTPS repositories, disables credentials and redirects, and reads and analyzes only exact pinned source snapshots without executing module code.