Module: RailsAiBridge::Registry

Defined in:
lib/rails_ai_bridge/registry.rb,
lib/rails_ai_bridge/registry/lockfile.rb,
lib/rails_ai_bridge/registry/resolver.rb,
lib/rails_ai_bridge/registry/truncatable.rb,
lib/rails_ai_bridge/registry/policy_error.rb,
lib/rails_ai_bridge/registry/pack_detector.rb,
lib/rails_ai_bridge/registry/pack_resolver.rb,
lib/rails_ai_bridge/registry/source_parser.rb,
lib/rails_ai_bridge/registry/tile_manifest.rb,
lib/rails_ai_bridge/registry/timeout_error.rb,
lib/rails_ai_bridge/registry/protocol_error.rb,
lib/rails_ai_bridge/registry/rake_presenter.rb,
lib/rails_ai_bridge/registry/resolver_cache.rb,
lib/rails_ai_bridge/registry/endpoint_policy.rb,
lib/rails_ai_bridge/registry/pack_definition.rb,
lib/rails_ai_bridge/registry/connection_error.rb,
lib/rails_ai_bridge/registry/context_tool_spec.rb,
lib/rails_ai_bridge/registry/message_sanitizer.rb,
lib/rails_ai_bridge/registry/registry_manifest.rb,
lib/rails_ai_bridge/registry/remote_tool_error.rb,
lib/rails_ai_bridge/registry/context_aggregator.rb,
lib/rails_ai_bridge/registry/frontmatter_parser.rb,
lib/rails_ai_bridge/registry/authentication_error.rb,
lib/rails_ai_bridge/registry/pinning_http_adapter.rb,
lib/rails_ai_bridge/registry/skill_source_resolver.rb,
lib/rails_ai_bridge/registry/context_provider_error.rb,
lib/rails_ai_bridge/registry/provider_request_scope.rb,
lib/rails_ai_bridge/registry/context_provider_client.rb,
lib/rails_ai_bridge/registry/response_too_large_error.rb,
lib/rails_ai_bridge/registry/context_provider_definition.rb

Overview

Registry resolution system for skill packs.

Provides priority-based loading of skill packs from git repositories, deprecation redirect handling, and framework auto-detection.

Defined Under Namespace

Modules: GitRunner, MessageSanitizer, SourceParser, Truncatable Classes: AgentEntry, AuthenticationError, ConnectionError, ContextAggregator, ContextProviderClient, ContextProviderDefinition, ContextProviderError, ContextToolSpec, DefaultGitRunner, DeprecatedEntry, DetectedFramework, EndpointPolicy, FrontmatterParser, LoadedPack, Lockfile, PackDefinition, PackDetector, PackResolver, PinningHttpAdapter, PolicyError, ProtocolError, ProviderRequestScope, RakePresenter, RegistryManifest, RemoteToolError, ResolvedSkill, Resolver, ResolverCache, ResponseTooLargeError, SkillEntry, SkillSourceResolver, SkillSummary, TileManifest, TimeoutError

Constant Summary collapse

REQUEST_RESOLVER_KEY =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Thread-local key for the request-scoped resolver.

:rails_ai_bridge_request_resolver

Class Method Summary collapse

Class Method Details

.build_resolver(config = RailsAiBridge.configuration.registry) ⇒ Resolver?

Builds (or returns a cached) Resolver from the current Config::Registry.

The first call for a given TTL window loads the manifest from disk, wires the SkillSourceResolver and PackResolver pipeline, and caches the result. Subsequent calls within the TTL window return the same resolver without I/O.

When inside a with_request_resolver block, the first successful build is memoized for the remainder of the request so multiple tool calls in the same request cycle share a single resolver without risking a mid-request rebuild.

Returns nil when the registry manifest file does not exist, allowing callers to surface a helpful setup message rather than raising. A nil result is never cached — the next call will retry.

archspec:disable dependencies.forbid -- FP: RailsAiBridge namespace accessor, not a cross-component dependency archspec:disable dependencies.no_cycles -- FP: cycle from namespace reopening, not a real cross-component cycle

Parameters:

Returns:

  • (Resolver, nil)

    wired resolver, or nil if manifest file is missing



128
129
130
131
132
133
134
135
136
# File 'lib/rails_ai_bridge/registry.rb', line 128

def self.build_resolver(config = RailsAiBridge.configuration.registry)
  # archspec:enable dependencies.forbid
  # archspec:enable dependencies.no_cycles
  return request_resolver if request_resolver?

  resolver = resolver_cache.fetch(config) { build_resolver_uncached(config) }
  store_request_resolver(resolver) if request_active?
  resolver
end

.clear_request_resolver!void

This method returns an undefined value.

Clears the request-scoped resolver for the current thread, if any.



106
107
108
# File 'lib/rails_ai_bridge/registry.rb', line 106

def self.clear_request_resolver!
  Thread.current[REQUEST_RESOLVER_KEY] = nil
end

.invalidate_resolver_cache!void

This method returns an undefined value.

Discards the cached resolver so the next build_resolver call rebuilds from disk.

Call this after clearing the git cache or modifying the registry manifest at runtime.



83
84
85
# File 'lib/rails_ai_bridge/registry.rb', line 83

def self.invalidate_resolver_cache!
  @resolver_cache_mutex.synchronize { @resolver_cache&.invalidate! }
end

.resolver_cacheObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the module-level ResolverCache instance, creating it on first call.



72
73
74
75
76
# File 'lib/rails_ai_bridge/registry.rb', line 72

def self.resolver_cache
  @resolver_cache_mutex.synchronize do
    @resolver_cache ||= ResolverCache.new
  end
end

.with_request_resolver { ... } ⇒ Object

Wraps a block in a request scope so that build_resolver is called at most once per request cycle. The first build_resolver call within the block stores the result in a thread-local; subsequent calls return the same resolver without touching the TTL cache. The thread-local is always cleared when the block exits, even on error.

Yields:

  • block to execute within the request scope

Returns:

  • (Object)

    the block result



95
96
97
98
99
100
101
# File 'lib/rails_ai_bridge/registry.rb', line 95

def self.with_request_resolver
  previous = Thread.current[REQUEST_RESOLVER_KEY]
  Thread.current[REQUEST_RESOLVER_KEY] = REQUEST_ACTIVE_SENTINEL
  yield
ensure
  Thread.current[REQUEST_RESOLVER_KEY] = previous
end

.write_lockfile(config = RailsAiBridge.configuration.registry) ⇒ void

This method returns an undefined value.

Writes a lockfile containing the current HEAD commit SHA for every pack in the registry manifest.

archspec:disable-next-line dependencies.forbid -- FP: RailsAiBridge is the reopened gem namespace; .configuration accessor is not a cross-component dependency

Parameters:

Raises:

  • (ArgumentError)

    when the manifest file does not exist



171
172
173
174
175
176
177
178
179
180
# File 'lib/rails_ai_bridge/registry.rb', line 171

def self.write_lockfile(config = RailsAiBridge.configuration.registry)
  manifest_path = config.registry_manifest_path
  raise ArgumentError, "Registry manifest not found at #{manifest_path}" unless File.exist?(manifest_path)

  manifest = RegistryManifest.from_file(manifest_path)
  git_runner = DefaultGitRunner.new(timeout: config.git_timeout)
  source_resolver = SkillSourceResolver.new(config.skill_cache_dir, git_runner, pull_ttl: config.git_pull_ttl)

  Lockfile.write(config.lockfile_path, manifest, source_resolver)
end