Redouble AI Nucleo documentation
Part 9 · Hosting Nucleo

Settings: where to tune anything

ai.redouble.nucleo · nucleo-core

A deployment of Nucleo has a handful of things it may want to change: how many HTTP connections the process opens at once, where credentials come from, how many MCP server processes may run side by side, which model catalog to read. Each of them is a public field on a settings class that sits beside the code it governs, with the value it ships with written inline. So the question "where do I tune X?" always has the same answer: in the settings class of the package that owns X.

Your application changes the fields it cares about in one place. In a plain Java application that place is one class you write, the configurator. In a Spring Boot or Quarkus application it is usually the application's properties file, and you write no class at all.

Reading and changing a setting

Settings.get(HttpSettings.class) returns the one instance of HttpSettings in the process, and its fields are plain public fields:

Settings.get(HttpSettings.class).poolSize = 2000;

Each field's javadoc says when the runtime reads it. Many are read once, when the part they govern is first built (the HTTP pool reads poolSize when it builds), so a setting is changed at startup, before any work runs. That is what the configurator is for.

The configurator

A configurator is a class implementing NucleoConfigurator. Its one method, configure(), assigns the settings that differ from the shipped values:

public class AcmeConfigurator implements NucleoConfigurator {
    @Override public void configure() {
        Settings.get(SecretsSettings.class).secretsClass = AcmeSecrets.class;
        Settings.get(HttpSettings.class).poolSize = 2000;
    }
}

The runtime finds it by itself and runs it once, the first time anything anywhere calls Settings.get, before that call returns. It looks in this order:

  1. The class named by the system property -Dnucleo.env, which wins over any registration.
  2. Else the single class listed in META-INF/services/ai.redouble.nucleo.NucleoConfigurator.
  3. Else none: the shipped values stand, and the log says so.

Three rules follow from there being one configurator per deployment:

The Spring Boot starter and the Quarkus extension each register a configurator of their own, which points the credential store at the application's properties. Naming your own class with -Dnucleo.env replaces theirs, so yours then sets the credential store as well (Spring Boot, Quarkus).

Settings as properties in Spring Boot and Quarkus

In a Spring Boot or Quarkus host, every field of every registered settings class binds from a property under nucleo.: the settings class's simple name without Settings, then the field, both written in kebab case. HttpSettings.poolSize is nucleo.http.pool-size:

nucleo:
  http:
    pool-size: 2000

A field may be a primitive or its box, a String, or a Class, which binds from a fully qualified class name. Properties are bound after the configurator runs, so where both set a field the property wins.

What you can tune

SettingPropertyWhat it changesShipped value
SecretsSettings.secretsClassnucleo.secrets.secrets-classthe store every credential is read from (Credentials)EnvironmentSecrets
ModelSettings.backendClassnucleo.model.backend-classwhere the model catalog is read from (The catalog, grades and the picker)JsonModelsBackend
ModelSettings.pickerClassnucleo.model.picker-classwhich picker turns a grade into a modelDefaultModelPicker
ModelSettings.mantleLaxProjectnucleo.model.mantle-lax-projectthe Bedrock Mantle project whose data retention mode is provider_data_share; models that require data sharing are served only under itnone
ModelSettings.mantleStrictProjectnucleo.model.mantle-strict-projectthe Bedrock Mantle project whose data retention mode is none; when set, every Mantle request for a model that does not require data sharing is pinned to itnone
HttpSettings.poolSizenucleo.http.pool-sizethe size of the one shared HTTP connection pool (The HTTP connection pool)1000
McpSettings.stdioPoolMaxnucleo.mcp.stdio-pool-maxhow many MCP server subprocesses may be in use at once, process-wide (Calling MCP servers)20
McpSettings.stdioMaxConcurrentPerEndpointnucleo.mcp.stdio-max-concurrent-per-endpointthe same, for one server10
McpSettings.stdioIdleTimeoutSecondsnucleo.mcp.stdio-idle-timeout-secondshow long an idle MCP subprocess is kept before it is stopped300
McpSettings.descMaxCharsnucleo.mcp.desc-max-charsthe longest description of a remote MCP tool shown to a model4096
DatabaseSettings.namenucleo.database.namethe name the application's database is registered under (Admission)default
DatabaseSettings.maxConcurrentnucleo.database.max-concurrenthow many jobs may use the application's database at once; unset registers no databaseunset
AnthropicSettings.connectionPoolSizenucleo.anthropic.connection-pool-sizethe idle connections kept by the Anthropic SDK client, in nucleo-provider-anthropic200

Seeing the whole configuration

NucleoConfigurator.printAll() returns every registered settings class with every field's current value, one line each, including the settings of jars other than nucleo-core. Logging it at startup shows what the deployment actually runs with.

Settings of your own library

A library with knobs of its own follows the same pattern: one subclass of Settings per package that owns knobs, named <Area>Settings, with plain mutable public fields and their defaults inline, and one line naming it in META-INF/services/ai.redouble.nucleo.Settings. That line is what lets printAll() list it and what lets the Spring Boot and Quarkus hosts bind its properties.

Numbers that are not settings

A number that is part of a contract is a constant, and no setting changes it: EmbeddingsClient.DIMENSIONS (stored vectors are that wide, and changing it is a migration), SingleObjectiveThinker.DEFAULT_MAX_ITERATIONS (the per-instance setMaxIterations is the real knob), JobDispatcher.DEFAULT_SHUTDOWN_TIMEOUT_MS (a caller of shutdown(ms) passes its own number).

How it works inside

The tests that pin the discovery rules and printAll are listed in Inside settings, for those working on the runtime itself.

^