rototo
Concepts

Why rototo

Runtime configuration starts small.

A team needs one value to change without rebuilding or redeploying the application: a token limit, a timeout, a model name, a feature toggle, a queue name, a support message. The first version is usually a constant, an environment variable, a flag rule, a JSON file, or a row in a database.

That works while the configuration is simple and changes rarely. It starts to break when the value becomes a decision: different answers for different environments, accounts, requests, or rollout states.

rototo exists for that point in the lifecycle. It gives runtime configuration a single source-controlled place to be described, reviewed, validated, tested, loaded by applications, and inspected when production behavior is surprising.

How Runtime Configuration Usually Grows

Consider an LLM summarizer. The first configuration value might be:

max_output_tokens = 2000

Then reality arrives:

None of those requirements are unusual. They are what happens when a runtime decision becomes important.

Teams often respond by adding more places where configuration can live:

Each tool can be reasonable on its own. The problem is not that environment variables, feature flags, config tables, or JSON files are bad. The problem is that one production decision is now split across several places.

To understand what the application will do, a human or agent has to reconstruct the answer from code, deployment state, dashboards, database rows, and tribal knowledge.

Where This Breaks Down

The failure mode is loss of control over a runtime decision.

Once the decision is scattered, teams can still change values, but they lose the two controls they rely on for production code: validation before release and reviewable change history. That is where runtime configuration becomes risky. The common failure modes are:

The point is not that every config value needs a heavy process. The point is that once a runtime configuration decision affects production behavior, the team needs a place where that decision can be reviewed and explained as a whole.

What rototo Changes

rototo addresses those failure modes by putting the runtime decision in one workspace that the CLI, CI, agents, and application SDK can all load.

The rototo Model

rototo uses a small model to make those changes concrete.

A workspace is the outer boundary. It is a directory tree of configuration files that can be reviewed, linted, tested, and loaded by applications.

Inside the workspace, variables define what application code can ask for. A variable such as max-output-tokens or llm-agent-config is the stable application-facing name. It also declares the type or schema of the value the application receives.

Variables are resolved in an environment. The environment is the deployment or runtime lane, such as dev, stage, or prod. That gives the same variable different behavior in different lanes without changing application code.

Resolution can also use runtime context. Context is the JSON facts the application provides for a request, account, tenant, user, or operation. Context lets configuration depend on real runtime information without hiding those inputs in unrelated systems.

Qualifiers give names to conditions over that context. A qualifier such as enterprise-accounts can represent "the account is enterprise and has enough seats." Variables can use qualifiers to select different values.

The selected branch inside a variable has a name. Names such as standard or large explain which branch produced the returned value. In CLI and JSON output, this selected branch name appears as value_key.

The entities relate like this:

workspace
  |
  +-- environments
  |     +-- dev
  |     +-- stage
  |     +-- prod
  |
  +-- variables
  |     +-- max-output-tokens
  |           +-- values: small, standard, large
  |           +-- env mapping: dev -> small, prod -> large
  |           +-- rules can select values by qualifier
  |
  +-- qualifiers
  |     +-- enterprise-accounts
  |           +-- predicates over runtime context
  |
  +-- schemas
        +-- context schema
        +-- variable value schemas

runtime request
  |
  +-- variable id: max-output-tokens
  +-- environment: prod
  +-- context: account plan, account seats, request country

Those two sides meet during resolution. The application does not read workspace files directly and it does not reimplement the rules. It sends a variable id, environment, and context to rototo. rototo uses the workspace to validate the inputs, evaluate any matching qualifiers, choose a value branch, validate the selected value, and return the value to the application.

workspace + variable id + environment + context
  -> validate inputs
  -> evaluate qualifiers
  -> select value branch
  -> validate selected value
  -> return value

This is why rototo is not just a lookup table.

A lookup asks:

What is the value for max-output-tokens?

That question assumes there is one answer. Runtime configuration often has more than one valid answer, depending on the environment and request context.

Resolution asks:

Given this workspace, environment, and request context,
which reviewed branch applies, and what value should the application receive?

In the running example, resolution can return both the selected branch name and the value:

resolve max-output-tokens for prod given this request context
  -> selected branch: large
  -> value: 2000

The selected branch, large, tells humans and tools why this path was taken. The value, 2000, is what application code uses.

The same model is available through the CLI and the SDK. That means local debugging, automated checks, agents, and application runtime all use the same source of truth.

Runtime Architecture

rototo configuration does not have to be fixed at application deployment time. The usual production shape is to deploy the configuration workspace separately from the application binary.

The application is deployed with a workspace source, such as a Git URI. At startup, the SDK loads that workspace. While the application is running, it can periodically refresh the workspace from the same source and keep serving the last successfully loaded version.

configuration repo
  |
  |  pre-push validation, CI, review, merge
  v
Git branch or tag
  |
  |  workspace URI
  |  git+https://github.com/acme/runtime-config.git#prod:config
  v
application deployment
  |
  |  app binary + workspace URI
  v
running application instances
  |
  +-- SDK loads workspace at startup
  +-- SDK refreshes workspace periodically
  +-- request handling resolves variables from latest good workspace
  +-- failed refresh keeps last good workspace active

That separation is important. Application deployments decide which workspace source to trust. Configuration releases update what that source contains. The application can pick up reviewed configuration changes without rebuilding or redeploying the application, while still keeping a controlled source, validation checks, and rollback through Git.

How the Model Helps

The model is useful because it turns runtime configuration back into something that can be checked before release.

Validation starts at the workspace boundary. The CLI can lint the manifest, check variable types, validate schemas, reject unknown environments, and catch rules that point at missing values. A context schema can reject malformed runtime context before rules are evaluated, preventing silent fallthrough to a default branch. Custom lint can enforce local policy, such as allowed model families or token budgets. That moves many configuration failures from production runtime to review or CI.

Because the workspace is source-controlled, configuration changes also get a review history. A change to a variable, qualifier, schema, or environment mapping can be reviewed as a diff, tested before merge, released intentionally, and rolled back like source code.

Variables give application code a contract. Instead of reaching into a bag of loosely named keys, the application resolves a stable variable id. The variable declares what kind of value it can return, so the workspace and the application can agree on shape before the value is used.

Values can stay inline for small decisions, or move into per-value TOML files when they are large structured objects. In both cases, resolution sees the same model: a variable selects a value key, and the selected key points at the value the application receives.

Environment and context make the inputs explicit. The answer may depend on prod, account plan, request country, tenant tier, or rollout state, but those inputs are passed into resolution directly. They are no longer hidden across deployment state, dashboards, database rows, and ad hoc overrides.

Qualifiers and selected branch names make the result explainable. A qualifier names the condition that matched, and the branch name identifies the selected path. That gives tests, logs, diagnostics, and agents something better to report than a raw value: they can explain why the value was returned.

When rototo Fits

rototo is a good fit when runtime configuration has enough meaning that it deserves source control and validation.

Use it for:

rototo is especially useful when you want local CLI checks, CI validation, and application runtime to share the same model.

When rototo Is Not the Right Tool

rototo is not meant to own every kind of runtime state.

Do not use it as:

rototo controls reviewed configuration decisions. It should not become the database for operational facts.

What to Read Next

Read quickstart if you want the shortest working example: create a local workspace, define one variable, lint it, and resolve it.

Read production-workflow if you want to see the same model with Git, context schemas, qualifiers, tests, application loading, refresh, custom lint, and observability.

Read the reference pages when you need exact CLI, SDK, file format, or diagnostic behavior.