manage-run-config

Run configuration handling for persistent command configuration storage

SKILL.md

GitHub

Manage Run Config Skill

Run configuration handling for persistent command configuration storage.

Enforcement

Base contract: See manage-contract.md for shared enforcement rules, TOON output format, and error response patterns.

Skill-specific constraints:

  • Do not bypass initialization (run-config.json must exist before queries)
  • Timeout and warning operations use the noun-verb pattern (e.g., timeout get, warning add)
  • Cleanup operations use cleanup and cleanup-status subcommands
  • Architecture-refresh operations use the noun-verb pattern (architecture-refresh get-tier-0, architecture-refresh set-tier-0, etc.)
  • CI-duration operations use the noun-verb pattern (ci-duration record, ci-duration p50)
  • Commit-trailer operations use the noun-verb pattern (commit-trailer get, commit-trailer set)
  • Registry-repin operations use the noun-verb pattern (registry-repin get, registry-repin set)

Run Configuration Structure

{
  "version": 1,
  "commands": {
    "<command-name>": {
      "last_execution": {"date": "...", "status": "SUCCESS|FAILURE"},
      "acceptable_warnings": [],
      "skipped_files": []
    }
  },
  "maven": {
    "acceptable_warnings": {
      "transitive_dependency": [],
      "plugin_compatibility": [],
      "platform_specific": []
    }
  },
  "architecture_refresh": {
    "tier_0": "enabled",
    "tier_1": "prompt"
  },
  "ci_durations": {
    "<command-name>": [420, 380, 455]
  },
  "commit_trailer": {
    "name": "plan-marshall",
    "email": "noreply@cuioss.de"
  },
  "registry_repin": "disabled",
  "ci": {
    "authenticated_tools": [],
    "verified_at": null
  },
  "derivation_resolvers": {
    "<resolver-id>": {"enabled": false}
  }
}

See standards/run-config-standard.md for complete schema.


Scripts

Script Notation
init plan-marshall:manage-run-config:run_config init
validate plan-marshall:manage-run-config:run_config validate
timeout get plan-marshall:manage-run-config:run_config timeout get
timeout measured plan-marshall:manage-run-config:run_config timeout measured
timeout set plan-marshall:manage-run-config:run_config timeout set
warning add plan-marshall:manage-run-config:run_config warning add
warning list plan-marshall:manage-run-config:run_config warning list
warning remove plan-marshall:manage-run-config:run_config warning remove
architecture-refresh get-tier-0 plan-marshall:manage-run-config:run_config architecture-refresh get-tier-0
architecture-refresh set-tier-0 plan-marshall:manage-run-config:run_config architecture-refresh set-tier-0
architecture-refresh get-tier-1 plan-marshall:manage-run-config:run_config architecture-refresh get-tier-1
architecture-refresh set-tier-1 plan-marshall:manage-run-config:run_config architecture-refresh set-tier-1
ci-duration record plan-marshall:manage-run-config:run_config ci-duration record
ci-duration p50 plan-marshall:manage-run-config:run_config ci-duration p50
language-server get plan-marshall:manage-run-config:run_config language-server get
language-server set plan-marshall:manage-run-config:run_config language-server set
language-server list plan-marshall:manage-run-config:run_config language-server list
language-server remove plan-marshall:manage-run-config:run_config language-server remove
derivation-resolver get plan-marshall:manage-run-config:run_config derivation-resolver get
derivation-resolver set plan-marshall:manage-run-config:run_config derivation-resolver set
derivation-resolver list plan-marshall:manage-run-config:run_config derivation-resolver list
derivation-resolver remove plan-marshall:manage-run-config:run_config derivation-resolver remove
display-timezone get plan-marshall:manage-run-config:run_config display-timezone get
display-timezone set plan-marshall:manage-run-config:run_config display-timezone set
commit-trailer get plan-marshall:manage-run-config:run_config commit-trailer get
commit-trailer set plan-marshall:manage-run-config:run_config commit-trailer set
registry-repin get plan-marshall:manage-run-config:run_config registry-repin get
registry-repin set plan-marshall:manage-run-config:run_config registry-repin set
cleanup plan-marshall:manage-run-config:run_config cleanup
cleanup-status plan-marshall:manage-run-config:run_config cleanup-status

Script characteristics:

  • Uses Python stdlib only (json, argparse, pathlib)
  • All commands output TOON to stdout
  • Exit code 0 for success, 1 for errors
  • Supports --help flag

Calling convention: All commands use plan-marshall:manage-run-config:run_config {command}. The cleanup module is integrated into run_config as cleanup/cleanup-status subcommands.


Standards

Document Purpose When to Read
run-config-standard.md Schema, timeouts, warnings, cleanup Full run configuration reference

Operations

Script: plan-marshall:manage-run-config:run_config

init

Initialize run-config.json with defaults.

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config init

validate

Validate configuration structure.

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config validate --file run-configuration.json

timeout get / measured / set

Manage adaptive command timeouts. Every value on this surface is in SECONDS — the persisted field is timeout_seconds, and --default, --explicit, and --duration are all seconds, never milliseconds.

Resolution order for timeout get:

  • --explicit N supplied → N overrides the persisted learned value outright; no learned value can reduce it.
  • --explicit omitted → the persisted learned value applies (scaled by the safety margin), falling back to --default when nothing is persisted.
  • A 120-second floor binds on both paths — an explicit bound does not waive it, because the floor protects against under-specification.
# Get current timeout for a command (--default: fallback seconds when unlearned)
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config timeout get \
  --command mvn-verify --default 300

# Override the learned value with an explicit bound (seconds)
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config timeout get \
  --command mvn-verify --default 300 --explicit 1800

# Record an observed duration (seconds) into the adaptive value
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config timeout set \
  --command mvn-verify --duration 180

# Ask whether a key has EVER been measured (raw persisted value, unscaled/unfloored)
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config timeout measured \
  --command mvn-verify

timeout measured answers a question timeout get structurally cannot: get returns an int for a measured and an unmeasured key alike, so its value carries no signal about whether the command has ever been observed. measured returns measured: true|false plus the RAW persisted timeout_seconds (null when unmeasured), with neither the safety margin nor the 120 s floor applied — any adjustment would blur the distinction the verb exists to expose. Its consumer is the execution_tier fail-closed rule in manage-architecture § Lookup Path: an unmeasured build command routes to the orchestrator rather than being run in-leaf on an unobserved first run.

warning add / list / remove

Manage acceptable build warning patterns.

# Add an acceptable warning
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config warning add \
  --category transitive_dependency --pattern "jakarta.json-api"

# List warnings for a category
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config warning list \
  --category transitive_dependency

# Remove a warning pattern
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config warning remove \
  --category transitive_dependency --pattern "jakarta.json-api"

architecture-refresh get-tier-0 / set-tier-0 / get-tier-1 / set-tier-1

Manage the architecture_refresh tier knobs consumed by the phase-6-finalize architecture-refresh step. Defaults are returned when the section is absent — init does not need to materialise the section. Tier-0 controls the deterministic architecture discover --force step (default enabled); Tier-1 controls LLM re-enrichment (default prompt).

# Read current tier settings (defaults: tier_0=enabled, tier_1=prompt)
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config architecture-refresh get-tier-0
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config architecture-refresh get-tier-1

# Disable the deterministic refresh entirely
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config architecture-refresh set-tier-0 \
  --value disabled

# Switch LLM re-enrichment to fully automatic (prompt|auto|disabled)
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config architecture-refresh set-tier-1 \
  --value auto

Allowed values:

  • tier_0: enabled, disabled
  • tier_1: prompt, auto, disabled

Invalid values surface the standard status: error, error: invalid_value, allowed: [...] contract.

The build-queue reap threshold is not a run-config knob

The adaptive stale-reclaim threshold the self-healing build-queue reaper measures an active slot against is machine-global, so this surface does not manage it. It is the top-level upper_limit_seconds field of ~/.plan-marshall/build-queue.json — the same file whose entries it governs — read and recomputed inside that queue's own critical section, and managed with plan-marshall:manage-locks:build_queue limit get / limit set --value N. The threshold applies to EVERY repository's entries in the one shared queue, which is why it belongs to the queue rather than to any one caller's repository; see manage-locks/SKILL.md § "The cap and the reap threshold are machine-global".

A build.queue.upper_limit_seconds key sitting in a repository's run-configuration.json has no effect on the applied threshold: build_queue limit get reports it as per_repo_value with in_effect: false.

ci-duration record / p50

Manage the bounded rolling window of observed successful CI-run durations that seeds the adaptive CI-wait first-sleep. Durations are persisted per command key under the top-level ci_durations map (mirroring the commands keyed shape) in the main-anchored run-configuration.json, so reads/writes resolve against the main checkout regardless of caller cwd. record appends the observed duration and bounds the window to the newest CI_DURATION_WINDOW_SIZE (default 5) entries, evicting the oldest. p50 returns the median of the window as the first-sleep seed — p50_seconds: null when the window is empty or absent (the consumer skips the seed on a null signal).

# Record an observed successful CI-run duration (seconds) into the key's window
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config ci-duration record \
  --command ci:wait --duration 420

# Get the p50 (median) seed for the key (p50_seconds: null on an empty window)
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config ci-duration p50 \
  --command ci:wait

For an odd-sized window p50_seconds is the middle observed duration; for an even-sized window it is the mean of the two middle values.

language-server get / set / list / remove

Manage the machine-local language_servers binding read by the lsp-client skill — the language-to-server map a phase-5-execute leaf uses for opt-in symbol lookup and verified edits. The binding is machine-local (server availability is per-machine tooling) and lives under the top-level language_servers map in the main-anchored run-configuration.json. An absent or enabled: false language is not configured, and lsp-client degrades to the Read / Edit path. See run-config-standard.md § "Language-Servers Section" for the schema.

# Bind a language server (--command is a JSON array of strings)
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config language-server set \
  --language python --command '["pyright-langserver", "--stdio"]' --language-id python

# Read the binding for a language (configured: false when absent)
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config language-server get \
  --language python

--disabled on set stores the binding but leaves it inactive; list reports the configured language keys; remove deletes a binding.

derivation-resolver get / set / list / remove

Manage the machine-local derivation_resolvers binding deciding which derivation resolvers run in this checkout. It is machine-local for the same reason language_servers is — a resolver's availability and cost depend on locally-installed tooling — and it lives beside that binding under the top-level derivation_resolvers map in the main-anchored run-configuration.json, not in a parallel store. See run-config-standard.md § "Derivation-Resolvers Section" for the schema and extension-api for the seam.

⛔ An unconfigured resolver is ACTIVE. A discovered resolver runs unless an entry explicitly disables it, so a project that never configures anything still derives its edges. Every read failure fails open for the same reason.

# Switch a resolver off for this checkout
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config derivation-resolver set \
  --resolver lsp --disabled

# Read the effective state (configured: false when no well-formed dict entry exists)
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config derivation-resolver get \
  --resolver markdown

The key is the resolver id, not a file pattern: a resolver returns (module, module) pairs carrying no file provenance, so there is no dispatch point at which a per-file binding could apply. list reports every entry the store holds — each with its own configured flag, so a malformed entry is shown rather than hidden and still reads configured: false (empty means everything is active); remove returns a resolver to default-active. To see the discovered resolvers joined against this binding — the roster the configuration menu renders — use extension-api:extension_api derivation-resolvers list.

display-timezone get / set

Manage the display-only render timezone — a single top-level display_timezone IANA zone name (default UTC). It is consumed exclusively at rendering surfaces to convert a stored UTC timestamp for human reading, and is never consulted on a write or compare path: storage and comparison stay UTC unconditionally. The default UTC makes the unset behaviour byte-identical to the pre-knob rendering, so no existing artifact changes unless the operator opts in. See run-config-standard.md § "Display-Timezone Section".

# Read the display timezone (default UTC when absent)
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config display-timezone get

# Set the display timezone (validated as an IANA zone name)
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config display-timezone set \
  --value America/New_York

set rejects a value that is not a loadable IANA zone with an invalid_value error and persists nothing.

commit-trailer get / set

Resolve the Co-Authored-By identity every assistant-authored commit ends with — a commit_trailer object holding name and email (defaults plan-marshall / noreply@cuioss.de). The identity names the system that produced the commit, never the assistant or vendor behind it, and it does not vary by target. See run-config-standard.md § "Commit-Trailer Section".

# Resolve the trailer and the source of each half
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config commit-trailer get

# Override either half, or both
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config commit-trailer set \
  --name my-system --email noreply@example.org

get returns name, email, the composed trailer, and name_source / email_source (configured or default). The two halves fall back independently, so a config carrying only a name yields a configured name beside a default email and reports exactly that. A stored value that is empty, not a string, or carries an angle bracket or line break is treated as absent — a malformed config degrades to the default identity rather than emitting a broken trailer line.

set requires at least one of --name / --email, applies the same fragment validation, additionally requires --email to contain @, and persists nothing on rejection.

Because run-configuration.json is git-ignored, a fresh clone and every cloud session resolve to the defaults. That is why repository documentation states the default identity rather than a configured override.

registry-repin get / set

Manage the machine-local opt-in that lets the project-local finalize sync step write the plugin registry — a single top-level registry_repin value, enabled or disabled (default disabled). It is machine-local because the registry it gates is machine-local: the pin lives in the plugin manager's own file under the operator's home directory, so consent to rewrite it is a per-machine decision. It sits beside commit_trailer in the same main-anchored run-configuration.json. See run-config-standard.md § "Registry-Repin Section".

# Read the opt-in (default disabled when absent)
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config registry-repin get

# Allow the finalize sync step to repin the registry on this machine
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config registry-repin set \
  --value enabled

get returns value and source (configured or default). A missing key and a malformed stored value — a non-string, or a string other than enabled / disabled — both read as value: disabled with source: default, so a damaged store is never read as consent to write.

set rejects any value other than enabled / disabled with an invalid_value error and persists nothing.

The setting gates one write only. With disabled, the finalize sync step still runs the repin script in its report-only form and still reports the pin's state; it simply never passes --apply. It has no effect on a manual registry_pin.py --apply, which is the operator's own explicit act.

cleanup / cleanup-status

Directory cleanup using retention settings from marshal.json.

# Check what would be cleaned up
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config cleanup-status

# Run cleanup
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config cleanup

# Clean a single target
python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config cleanup --target no-plan-bodies

--target selects one of five cleanable targets, or all (the default) to run every one:

Target Retention knob Cleans
temp temp_on_maintenance The project-local .plan/temp/ scratch tree
logs logs_days Aged *.log files under the runtime logs directory
archived-plans archived_plans_days Aged archived-plan directories
no-plan-bodies no_plan_body_days Aged prepared CI body files (*.md) under the plan-less NO_PLAN sentinel
build-results build_results_days Aged build-result files under a NON-live plan's build-results/ tree, and under the NO_PLAN sentinel's

The no-plan-bodies target exists because the NO_PLAN sentinel is a shared, permanent plan directory that is never archived — archived_plans_days never reaches it, so without this target the body files plan-less callers prepare would accumulate indefinitely. It removes only the aged body files; the sentinel directory, its work/ subtree, and its status.json marker are never removed, and a missing sentinel directory is a clean no-op rather than an error.

The build-results target ages the per-plan build-output trees, and is guarded so it can never reap a running plan's results. It enumerates plan directories from the plan store and skips a LIVE plan's tree entirely — a plan is live for as long as its directory carries a status.json marker. A live plan's results appear in NEITHER the cleanup nor the cleanup-status population, so they are never counted as reclaimable rather than merely spared deletion. Only a plan directory whose status.json is absent, and the never-archived NO_PLAN sentinel, are subject to the age threshold; a finished plan is aged instead by archived_plans_days once archive-plan has moved it under archived-plans/.

See manage-config data-model.md § Retention Fields for the canonical knob semantics of both targets.


Error Responses

See manage-contract.md for the standard error response format.

Error Code Cause
key_not_found Configuration key doesn't exist
invalid_value Value fails type/enum validation (e.g., non-numeric timeout, architecture-refresh or registry-repin enum mismatch)
not_initialized run-config.json missing (run init first)
invalid_category Warning category not in: transitive_dependency, plugin_compatibility, platform_specific
marshal_not_found marshal.json missing (cleanup needs retention settings)

Integration

Producers

Client Operation Purpose
marshall-steward init Initialize run configuration during setup
marshall-steward architecture-refresh set-tier-0/1 Persist user-selected tier knobs from setup/maintenance wizard
Build skills timeout set Update timeouts after command execution
Build skills warning add Register acceptable warning patterns
CI-wait handlers (_github_ci, gitlab_ops) ci-duration record Record an observed successful CI-run duration into the p50 window on natural completion

Consumers

Client Operation Purpose
Build skills timeout get Read timeout values for command execution
manage-architecture _lookup_bash_timeout timeout measured Read measured-ness for the execution_tier fail-closed rule (unmeasured → orchestrator)
Build skills warning list Filter build warnings against accepted patterns
phase-6-finalize architecture-refresh step architecture-refresh get-tier-0/1 Read tier knobs to decide deterministic refresh / LLM re-enrichment behaviour
manage-locks build_queue limit get (reads the file directly) Report a surviving per-repo build.queue.upper_limit_seconds as per_repo_value with in_effect: false — a report only; it never resolves the applied threshold from here
CI-wait handlers (_github_ci, gitlab_ops) ci-duration p50 Read the p50 seed for the adaptive CI-wait first-sleep (skip on a null window)
workflow-integration-git commit workflow commit-trailer get Resolve the Co-Authored-By line appended at git commit time
project:finalize-step-sync-plugin-cache (the project-local finalize sync step) registry-repin get Decide whether the step's repin runs with --apply (enabled) or report-only (disabled)

Canonical invocations

The canonical argparse surface for run_config.py. The plugin-doctor missing-canonical-block rule checks that this section is PRESENT, matching its heading only — the body is never read; manage-invocation-invalid derives its accept-set from a live --help walk rather than from this section. Consuming docs xref this section by name instead of restating the command inline. See pm-plugin-development:plugin-script-architecture cross-skill-integration.md § "Script invocation in documentation".

init

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config init [--force]

validate

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config validate --file FILE

timeout

timeout carries the nested sub-verbs get, measured, and set:

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config timeout get \
  --command COMMAND --default DEFAULT [--explicit EXPLICIT]

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config timeout measured \
  --command COMMAND

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config timeout set \
  --command COMMAND --duration DURATION

DEFAULT, EXPLICIT, and DURATION are all in seconds. --explicit overrides the persisted learned value.

warning

warning carries the nested sub-verbs add, list, and remove:

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config warning add \
  --category {transitive_dependency,plugin_compatibility,platform_specific} --pattern PATTERN \
  [--build-system BUILD_SYSTEM]

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config warning list \
  [--category {transitive_dependency,plugin_compatibility,platform_specific}] [--build-system BUILD_SYSTEM]

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config warning remove \
  --category {transitive_dependency,plugin_compatibility,platform_specific} --pattern PATTERN \
  [--build-system BUILD_SYSTEM]

architecture-refresh

architecture-refresh carries the nested sub-verbs get-tier-0, set-tier-0, get-tier-1, and set-tier-1:

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config architecture-refresh get-tier-0

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config architecture-refresh set-tier-0 \
  --value {enabled,disabled}

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config architecture-refresh get-tier-1

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config architecture-refresh set-tier-1 \
  --value {prompt,auto,disabled}

ci-duration

ci-duration carries the nested sub-verbs record and p50:

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config ci-duration record \
  --command COMMAND --duration DURATION

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config ci-duration p50 \
  --command COMMAND

language-server

language-server carries the nested sub-verbs get, set, list, and remove:

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config language-server get \
  --language LANGUAGE

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config language-server set \
  --language LANGUAGE --command COMMAND [--language-id LANGUAGE_ID] [--disabled]

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config language-server list

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config language-server remove \
  --language LANGUAGE

derivation-resolver

derivation-resolver carries the nested sub-verbs get, set, list, and remove:

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config derivation-resolver get \
  --resolver markdown

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config derivation-resolver set \
  --resolver lsp --disabled

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config derivation-resolver list

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config derivation-resolver remove \
  --resolver lsp

display-timezone

display-timezone carries the nested sub-verbs get and set:

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config display-timezone get

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config display-timezone set \
  --value VALUE

commit-trailer

commit-trailer carries the nested sub-verbs get and set:

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config commit-trailer get

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config commit-trailer set \
  [--name NAME] [--email EMAIL]

registry-repin

registry-repin carries the nested sub-verbs get and set:

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config registry-repin get

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config registry-repin set \
  --value {enabled,disabled}

cleanup

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config cleanup \
  [--dry-run] [--target {all,temp,logs,archived-plans,no-plan-bodies,build-results}]

cleanup-status

python3 .plan/execute-script.py plan-marshall:manage-run-config:run_config cleanup-status

Related

  • manage-config — Project-level marshal.json configuration (provides retention settings)
  • manage-lessons — Complementary global persistence (lessons learned)