Skip to content

Latest commit

 

History

59 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Barn

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.

Source layout

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.

Public Go API

Barn exposes two reusable packages for CLIs and other Go tooling:

  • github.com/MontFerret/barn/pkg/registry consumes 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 as Version.Package.Path and absolute content artifact URLs; version summaries expose their immutable PublishedAt time. 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/publish validates 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.

API Reference authoring contract

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) error method performs registration, as used by the LLM module;
  • module-local helper calls across packages with statically propagated Library and Namespace("...") values;
  • sdk.RegisterFunctions with direct sdk.Func values, static composite slices, and static append composition;
  • sdk.Bind and sdk.Bind0 through sdk.Bind4;
  • direct Function().A0() through A4() and Var() builder chains with Add; 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.

Registering a module

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 publish

ferret 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.

Manual recovery and operator workflow

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.yaml and go.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.yaml exists at the repository root, or at the optional module source path in a monorepo;
  • a valid go.mod exists beside ferret.yaml, and its module directive is compatible with the release version;
  • a README.md containing the release documentation exists beside that ferret.yaml;
  • the module's Ferret registrations use one of the statically supported API Reference authoring forms above;
  • the manifest's name is the <owner>/<module> being registered and its version is 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}', replacing v1.2.3 with the release tag.
ferret mod publish

The 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>

Submitting the registration

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 check

Commit 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.

What happens after submission

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.

Development

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.

Trusted publication setup

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:

  1. Create a GitHub App named Ferret Barn Publisher with only the repository permission Contents: Read and write.
  2. Install the App only on MontFerret/barn.
  3. Store its App ID as the organization Actions secret BARN_PUBLISHER_APP_ID, with access limited to MontFerret/barn.
  4. Store its private key as the organization Actions secret BARN_PUBLISHER_PRIVATE_KEY, with the same repository restriction.
  5. Add Ferret Barn Publisher to the main and gh-pages branch ruleset bypass lists with Always allow; block contributor pushes, force pushes, and deletion of gh-pages.
  6. 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 source field.
  7. Run the CI workflow once with full_rebuild enabled to bootstrap gh-pages, then configure GitHub Pages to deploy from gh-pages at / while retaining registry.ferretlang.org and 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.

About

Ferret module registry and catalog. Barn provides a curated index of Ferret modules, their published versions, source locations, and metadata for discovery and installation.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages