Hamburger Cross Icon
moon Cataloger - Lunar Cataloger

moon Cataloger

⇄ Cataloger Beta Service CatalogVcs

Reads the dependency graph a monorepo already declares in its moon configuration and writes it into Lunar as component `paths`. Each component gains a path entry for every directory it transitively depends on, so a commit to a shared library re-evaluates every service that consumes it.

Add moon to your lunar-config.yml:
uses: github://earthly/lunar-lib/catalogers/moon@v1.0.5

What This Integration Syncs

This integration includes 1 cataloger that sync data from your systems.

Cataloger component-repo

dependency-paths

Runs once per component of a repository that just received a commit, with the repository checked out. Walks up for .moon/, runs moon query projects, and matches the component's subdirectory against each project's source. The matched project's transitive dependsOn closure becomes the component's paths — one <dir>/* glob per dependency reached. Its own directory is not written; the hub derives that implicitly from the component name. Skips silently when the component is the repository root, when there is no moon workspace, when the subdirectory is not a moon project, or when the project has no dependencies.

monorepo moon moonrepo dependency graph paths change detection shared library workspace
Book a demo

How Catalogers Fit into Lunar

Lunar catalogers sync component metadata into your Lunar catalog from external systems or source code. They can run on a schedule or be triggered by code changes to keep your service registry up-to-date.

By automatically discovering components from GitHub organizations, service registries, or by detecting technology usage in source code, catalogers ensure your guardrails apply to all relevant services without manual configuration.

Learn How Lunar Works →
1
⇄ Catalogers Sync Context This Integration
Sync component metadata from service catalogs, ownership systems, and external APIs
2
⚙ Guardrails Engine
Once cataloged, components are automatically analyzed by collectors and evaluated against your guardrails

Example Catalog Entry

This cataloger syncs component metadata into your Lunar catalog. Here's an example of a catalog entry it creates:

{ } catalog entry Catalog JSON
{
  "components": {
    "github.com/acme/monorepo/apps/web": {
      "paths": [
        "packages/auth/*",
        "packages/telemetry/*"
      ]
    }
  }
}

Configuration

Configure this cataloger in your lunar-config.yml.

Inputs

Input Required Default Description
require_dependency_edges Optional true Fail the run when moon reports several projects but no dependency edges at all. An unresolvable toolchain produces exactly that — moon exits 0 with an empty stderr — so the default refuses to publish it. Set to `false` for a workspace that genuinely declares no `dependsOn`.
exclude_scopes Required — Comma-separated moon dependency scopes to ignore, e.g. `development` to keep test-only dependencies out of a service's paths. Empty follows every edge moon reports.

Documentation

View on GitHub

moon Cataloger

Reads the dependency graph a monorepo already declares in its moon configuration and writes it into Lunar as component paths.

Overview

A component named after a subdirectory already matches changes under it, but Lunar does not know that apps/web consumes packages/auth — so a commit touching only the shared library leaves apps/web un-evaluated. Closing that gap means listing every dependency in the service's paths, which is fine for one edge and unmaintainable for a thousand. A monorepo on moon has already declared those edges in moon.yml, because its build depends on them being right. This cataloger reads that graph and generates the paths list from it.

paths gates policy evaluation, not data attribution: widening it re-runs a service's policies on a library change, but does not move a CI run's collected data onto that service.

Synced Data

Path Type Description
.components["<id>"].paths[] array One <dir>/* glob per project the component transitively depends on. Repo-relative, sorted, de-duplicated. The component's own directory is not written — the hub already derives an implicit <subdir>/* from the component name

Only paths is written — ownership, domains and tags come from whichever cataloger defines the component.

The hub appends arrays when merging, so these globs union with any paths declared in lunar-config.yml rather than replacing them. A path declared in both places appears twice — harmless for matching, but worth deleting from the config once this cataloger owns the list. (This is also why the component's own directory is omitted: the config sync materialises the implicit <subdir>/* onto every component, so emitting it here would duplicate it every time.)

Catalogers

Cataloger Description
dependency-paths Finds the moon project whose source is the component's subdirectory, takes its transitive dependsOn closure, and writes one <dir>/* glob per dependency reached

A trailing * is a prefix match in Lunar and it crosses /, so one glob per project covers every file beneath it. Where the moon workspace root sits below the repository root, each source is prefixed with that offset to keep the globs repo-relative.

Skips silently (exit 0, nothing written):

  • the component is the repository root — it already matches every path, so writing paths would narrow it
  • the repository has no .moon/ at or above the component directory
  • the component's subdirectory is not a moon project
  • the project has no dependencies once exclude_scopes is applied — there is nothing to add that the implicit <subdir>/* does not already cover

Fails the run (nothing written):

  • moon query projects errors or returns unparseable output
  • moon reports several projects and no dependency edges at all. An unresolvable toolchain looks exactly like that — moon exits 0 with an empty stderr and an edgeless graph — and publishing it would claim nothing in the repo depends on anything. Set require_dependency_edges: "false" for a workspace that genuinely declares none.

Hook Type

Cataloger Hook Schedule / Trigger Description
dependency-paths component-repo (clone-code: true) Every push to a component's repository Runs once per component of the pushed repo, with the repo checked out at the pushed commit

clone-code: true is what makes this work: moon reads moon.yml from a working tree, so the graph needs a real checkout rather than a GitHub API fetch. It needs no token and no network — moon is a single static binary and the declared edges come from files in the checkout — so it runs on air-gapped installs.

Being a per-component hook it augments components that already exist and cannot create them. Pair it with a component-defining cataloger such as github-org or backstage-catalog-info-monorepo, or declare the subcomponents in lunar-config.yml.

Installation

catalogers:
  - uses: github://earthly/lunar-lib/catalogers/moon@main

No secrets or inputs are required. To keep test-only dependencies out of a service's paths:

catalogers:
  - uses: github://earthly/lunar-lib/catalogers/moon@main
    with:
      exclude_scopes: "development"

Components whose paths should be managed must exist and be named after their subdirectory, e.g. github.com/acme/monorepo/apps/web for the moon project at apps/web.

Source System

moon — the moon binary is baked into this cataloger's image and runs against the checkout the hook provides. Requirements:

  • The repository uses moon: a .moon/workspace.yml and a moon.yml per project. Repos without one are skipped.
  • Project sources match component subdirectories. A moon project at apps/web maps to the component whose name ends /apps/web. A project that is not itself a Lunar component is still traversed as a dependency; it just gets no paths of its own.
  • Declared edges, not inferred ones. moon can also infer dependencies from a language's own manifests, but that needs the language toolchain in the cataloger image, which this plugin does not ship. Workspaces relying on inference see fewer edges, and the edgeless-graph guard above is what stops that failing silently.

Scope

Only moon is read today. The same three fields — project id, project directory, dependency ids — are what go list, cargo metadata, nx and turborepo all produce, so other graph sources belong behind this interface rather than in separate catalogers.

Auto-injecting moon into a repository that does not use it was prototyped and rejected: moon refuses to build a graph whose directory-level dependencies contain a cycle, which Go permits at package level, and silently reports zero edges when it cannot resolve a toolchain.

Open Source

This cataloger is open source and available on GitHub. Contribute improvements, report issues, or fork it for your own use.

View Repository

Ready to Automate Your Standards?

See how Lunar can turn your AGENTS.md, engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 200+ built-in guardrails.

Works with any process
check AI agent rules & prompt files
check Post-mortem action items
check Security & compliance policies
check Testing & quality requirements
Auto-ID My Guardrails
Paste your AGENTS.md or manual process doc and get guardrails in minutes
Book a Demo