Skip to content

Configuration_Guide

Configuration Guide

Two surfaces carry intent into a running godon. The systemtender config is YAML — what a tender measures and moves. A wish declaration is made at runtime — what a holder asks the system to keep, or to search.

Systemtender configuration is YAML with four concepts: objectives (the readings trials are judged on), guardrails (safety), observations (extra channels to read), and effectuation (the registered targets its acts land on). Parameters live under settings with per-parameter constraints. Interference characterization is a section, not a mode — every systemtender in a group walks and holds concurrently.


The Shape of a Systemtender Config

meta:
  configVersion: "0.3"
  strict_validation: false

systemtender:
  type: bench_generic

settings:                       # parameter search space
  generic:
    param_0:
      constraints:
        - {step: 20.0, lower: 0.0, upper: 100.0}
    param_1:
      constraints:
        - {step: 20.0, lower: 0.0, upper: 100.0}
    param_2:
      constraints:
        - {step: 20.0, lower: 0.0, upper: 100.0}

interference_detection:         # characterization group membership
  group: bench-characterization
  mode: active
  convergence_threshold: 0.02   # the ONE tuning knob
  refinement_depth: 3
  push_block_size: 10
  pause_block_size: 10
  cooldown_trials: 5
  hold_params:                  # neutral position for hold/pause blocks
    param_0: 50.0
    param_1: 50.0
    param_2: 50.0

reconnaissance:                 # how this systemtender reads its target
  type: http
  http:
    url: "http://bench-generic:8090/node-1"

objectives:                     # the readings trials are judged on
  - name: objective_0
    direction: maximize
    reconnaissance:
      service: http
      path: /metrics/json
      key: objective_0
      samples: 3
      aggregation: median

observations:                   # recorded but NOT judged — detection channels
  - name: objective_1
    reconnaissance:
      service: http
      path: /metrics/json
      key: objective_1

effectuation:                   # where its acts land
  targetRefs: [generic-node-1]  # registered targets, by name or ID

Sections

settings — the search space

Each parameter carries constraints. step sets the grid resolution; the characterization walk derives its level set from lower/upper (and refines between grid points when curves stay unresolved).

How a run ends

A systemtender runs until one of three things happens:

  • Work complete — the characterization has nothing left to measure (all parameters converged or the refinement depth is spent) and the systemtender finishes on its own
  • Stop requested — an explicit stop via the API: the current trial completes, then the systemtender finishes
  • Failure — the worker crashes

interference_detection — characterization

Any systemtenders sharing a group characterize each other. convergence_threshold is the single tuning knob: smaller means more re-measurement before a curve retires. Block sizes set the push/pause trial counts per probe. hold_params is the neutral position every systemtender returns to when holding or pausing.

objectives vs observations

The separation is deliberate and load-bearing: objectives carry each trial's judged values; observations are recorded per trial and never judged — the detector reads both. A channel you suspect is coupled but don't want driving trial outcomes should be an observation, not an objective.

reconnaissance

How a systemtender reads its target: HTTP endpoints (per-service path/key, sampling, aggregation), or Prometheus queries. See Reconnaissance.

effectuation and the targets catalog

A systemtender's acts land on targets from the targets catalog. Targets are registered at runtime — REST POST /targets or the target_create MCP tool — with a name, a targetType (ssh or http), and a spec (ssh carries an address, http carries a url). The config names them in effectuation.targetRefs, by name or ID; a config with no reference is refused at validation, before anything runs. What an act does once it lands is the Effectuator's story.

Guardrails

Safety limits with automatic response (fail trial, rollback, or skip target) are configured per strain and effectuator — see Guardrails. The impulse protocol's pushes stay inside the same guardrails as ordinary trials: same knobs, same bounds, no special permissions.


The Shape of a Wish Declaration

Wishes are declared at runtime, not written into a config file: a wish is a payload sent to the REST API (/wishes) or the wish_declare MCP tool. The payload states its type — steer (the hold) or seek (the walk), each with its own shape below. Both types also carry two family options: answer (now or later, default later — when the reachability consult answers) and standard (all or best — one kept state, or the best of several; holds default all, walks default best).

Steer — the hold's shape

One wish = one or more claims and optional terms, one verdict. Kept means every claim in its band and every term honored.

type: steer
claims:                        # the aims — N >= 1
  - outcome: chainend.shift
    band: {lo: -0.14, hi: -0.06, target: -0.10}
terms:                         # the protected readings — M >= 0
  - outcome: chainend.offset
    band: {lo: -0.02, hi: 0.02}
limits:
  exclude: [param_2]
  maxChange: 0.5
budget: 2
regime: standing

claims vs terms

Claims and terms share one shape — a named measured value plus a band — and mirror the objectives/observations split above: claims are what the wish keeps; terms are protected readings it must never push out of band while keeping them. A broken term is a miss with the same standing as a broken claim. Bands carry the outcome's own measurement units — the reading, never a movement. The target inside a band is for evidence and reporting, never judged.

The serving fields

  • limits — parameters excluded from movement, and a maximum change per act; checked at plan time, a refusal names the binding one
  • budget — the re-act allowance after drift events; omitted means upkeep indefinitely
  • regime — the closing rule; standing today (held until closed)

An unkeepable wish is refused by name before anything acts.

Seek — the walk's shape

A commissioned search: the region to walk, and either a criterion with a budget (find_best) or neither (cover_now, which walks to extend coverage and carries no budget). Semantics and lifecycle in Wish.

type: seek
form: find_best               # or cover_now — no criterion, no budget
region:
  chainend.push: [-0.4, 0.4]  # the dials to walk, each [lo, hi]...
  chainend.gain: [1, 8, true] # ...or [lo, hi, is_int] — whole numbers only
criterion:
  outcome: chainend.shift     # what counts: the reading
  direction: minimize         # ... and the direction
budget: 12                    # measured trials the walk may spend
candidates: 2                 # measured launch points — counted in the budget
answer: later                 # family option, both types — 'now' answers in the same breath
standard: best                # family option, both types — walks default to best

The walk is served, not aimed: the region's dials are a registered systemtender's own parameters, and the plan names the serving systemtender — a declaration never picks one itself.

A declared wish is a durable, withdrawable record — lifecycle, event history, and the holder's correction of a standing wish are covered in Wish.


Working Examples

Runnable, maintained examples live in the scenario library: examples/bench/ in the godon repository — each scenario ships systemtender configs, target definitions, and the planted ground truth. The characterization scenarios are the reference implementations for the config above. For wish declarations, examples/bench/scenario-wish-stack/ is the reference — a bench whose corridors couple the aims and the protected readings, so both claims and terms bind.


See Also