Skip to content

Configuration field reference ​

Init provisioning uses the same field validators as native git_workflow for delivery branch, private namespace, source roots and exclusions. Its four --git-* options are singleton/all-or-none; JSON path arrays preserve their exact order and entries. No implicit source/exclusion/branch value is supplied. Existing configurations are preserved, and supplied values must match their selected policy exactly. The classic-git registry entry has a provision-required builder, not a default effective config. Compilation selects its standalone prompt root, including the real Executor correction participant on every type. Selected role overrides must retain the native-source (card) or native-global capability include.

Native Git policy declarations ​

The strict source/effective git_workflow input has initial format_version: 1. Absence is OFF; explicit OFF is exactly {format_version: 1, enabled: false}. ON requires all of:

  • delivery_branch: literal attached branch name, not an OID, revision expression or full refs/heads/ ref;
  • private_ref_namespace: explicit namespace beneath refs/saivage/;
  • nonempty, duplicate-free source_roots and excluded_paths: literal relative paths (. denotes the project root), not globs or URLs; exclusions include .git and .saivage;
  • integration: squash and preservation: {source_checkpoint: eligible-worktree, interrupted_rebase: preserve-source-before-abort};
  • correction: {agent, prompt, correction_prompt}: an actual card Executor participant without child authority, with command/write tools and diagnostic git-correction.md permission; task and result-correction prompts use the existing static and durable declarations respectively;
  • review_bindings: every configured card type explicitly maps to {node, approved_outcome} or null for a type without review. Bound review uses unchanged descendant context and routes approval to DONE or root completion assessment. Every participating type declares nonbootstrap git-correction.md.

Compilation freezes a detached policy and rejects authored correction-node collisions/references, postcommit hooks and unsupported selected global writer surfaces. Public effective configuration exposes only version/enabled, not source paths, refs or correction provisioning. This validation is not native repository qualification, identity-scoped ref allocation, commissioning or source adoption.

The opt-in classic-git profile supports ON with explicit provisioning and fresh lifecycle-owned commissioning. Existing profiles remain OFF; there is no startup toggle or retained-state adoption. Do not add these declarations to a running project or interpret schema acceptance as successful repository commissioning.

The dependent native domain foundation currently qualifies an ordinary real-index checkout, checkpoints eligible final worktree bytes through that real index, and performs protected switches to an exact existing branch/tip. The initializer owns fresh commissioning; CardService publishes source facts. Checkpoint normalization discards the prior staging split; tracked/new/deleted files, executable bits and symlinks are source, while excluded or nonignored out-of-scope dirt refuses before checkpoint. Sparse/split indexes, submodules, filesystem-monitor hooks and non-round-tripping attributes are not supported. Source names must be UTF-8; native command output is bounded to 8 MiB. Git hooks are not disabled. Timeout, incomplete capture or unexpected mutation failure contains the attempt without retry or inferred source publication. Supervisor owns runtime native lifecycle, acceptance and source-fact publication; fresh commissioning belongs to the lifecycle-held initializer, not the first Run. Native entry derives refs/heads/saivage/<commissioned-namespace-suffix>/<card-id> and creates that exact branch only when absent. Retained originals use the distinct refs/saivage/<suffix>/retained/<card-id>/<invocation-uuid> namespace, create-only. Reentry replays explicit old B..C onto the exact current parent; after a previous delivery the delivered child endpoint replaces B as the replay boundary. Empty and reapplied owned commits are retained. An identified untouched native conflict is aborted and verified back at clean C before returning a correction task; hook or custom-driver involvement prevents that automatic-abort certification. Candidate preparation returns post-checkpoint source observations, not approval. Correction verification requires exact task/retained-original/parent identities, clean source and linear parent ancestry; it cannot prove semantic completeness. Only CardService publishes returned source facts. Native delivery requires the exact clean accepted child and parent tuple and materializes a squash in the real parent index. It commits only that staged accepted tree, not later worktree dirt; an unchanged tree makes no empty commit. Ordinary failure return checkpoints eligible source privately and switches back without merging it.

ON global source writes use final synchronous stopped/clean delivery admission, including delayed Webfetch saves and resolved aliases; OFF retains ordinary mid-run behavior. Records and permitted non-source files are unaffected. Global command-backed quality, arbitrary commands and unknown MCP writers are rejected from actual provider bindings, not silently removed. Wait/kill process controls and read-only MCP discovery remain available, but no unknown writer can start. The MCP manager retains the startup mode across later configuration reads and rejects dynamic registration/replacement, start/restart, catalog refresh/invocation and enabled persisted reconciliation before connection or publication effects. This is not permission to edit policy on a commissioned project or adopt dirt.

Interrupted correction preservation has two independent owner calls, each using sequential direct managed Git commands rather than a subprocess coordinator. captureRebase leaves the actual rebase/index untouched, selects final eligible bytes/deletions/modes/symlinks through a fresh command-work index, and retains a native snapshot separately from original B..C. Its result names both the original task and partial snapshot plus the selected work artifact. Only successful caller source-fact publication and continuing settlement authority permit a separate restoreRebaseAndReturn invocation. That invocation rechecks exact task/snapshot and actual source with a fresh index, then aborts the identified rebase, restores the snapshot through native real-index/worktree restore, checkpoints it privately and returns to the unchanged parent. It never uses the first temporary index as authority or runs across a publication frontier. Source mismatch refuses before abort; later failure contains without retry or manual file cleanup.

A partial c1 snapshot may omit original c2. The original endpoint/ref and correction task remain retained: the snapshot is neither a new replay endpoint nor proof of semantic completeness. A later correction must reconstruct original work and useful resolutions while preserving parent-only work. Captures and returns consume only their exact identified task/native rebase; foreign or unexplained progress refuses. These steps use the native lifecycle owner and execution evidence. Fresh init commissions the root before publishing its initial head; retained state is never implicitly adopted. checkpoint_source is selected only for the bundle's Executor: an empty-argument private checkpoint, not delivery, review approval or a repair API.

Quality actions ​

Optional tool binding input ​

The source/effective agent input accepts optional quality_tools with explicit format_version: 1. It requires at least one of code_quality_javascript_eslint, code_quality_typescript_eslint, code_quality_python_ruff, whose values use the same strict action configs described below. Each binding requires that exact tool name in the agent's tools list, and a selected quality tool requires its binding. Unknown entries/versions fail. Omission configures and grants nothing. Outbound effective configuration omits the entire provisioning section, including paths and scope, while ordinary selected tool names remain visible.

Selected tools accept strict empty {} requests. They use only the configured policy agent's frozen bindings; requests cannot supply paths, executable/module names, operation IDs, scope, arguments or an output record. Card/global/internal Analyst and external Analyst calls use the same compiled operation and interpreter. External calls retain authentication and the configured Analyst/tool-subset policy; credential attribution does not select a different agent. Tool calls produce work evidence only, never a card execution entry or accepted action-output record. Action and tool configuration are alternatives, not a requirement to run both. The existing Oversight allowed-tool restriction is unchanged; this integration does not grant it command-capable quality tools.

Explicit contract1 operations are code-quality.javascript.eslint, code-quality.typescript.eslint and code-quality.python.ruff. No default workflow selects them and no agent tool grant is implied. Use execution.kind: action, inputs: {}, and optionally the ordinary output_record binding. See exact native prerequisites/licenses.

All three strict configs require cwd, native_config, nonempty source_paths, exclusions, timeout_ms (1–600000) and terminate_grace_ms (0–10000). Source/exclusion entries are exact files or directory roots, not globs. Paths are project-root-relative except executables; cwd: . is allowed. Runtime/private roots, credentials, blocked resolved aliases and containment escapes are refused. Unsupported/unmatched/ignored scope is incomplete analysis, not clean; explicit exclusions stay visible. Source traversal never inventories canonical state.

JS requires absolute node_binary and contained eslint_module package directory. TS additionally requires typescript_eslint_module, typescript_module package directories and exact tsconfig. Python requires absolute ruff_binary. Native configuration/imports/plugins are operator-authorized code, not request data or a sandbox. Exact consumed pins are ESLint10.13.0, typescript-eslint/parser8.72.0, TS5.9.3 and Ruff0.17.2. No PATH discovery, runtime installation or default grants.

Required outcomes: clean, findings, analysis_failed, timed_out, signalled. Each exposes finding_count, error_count, warning_count, analyzed_files, coverage_complete. Clean/findings lead to ordinary assessment, not automatic DONE. Cancellation is not an outcome. Warning-only ESLint exit0 can be findings; empty/incomplete scope, native failure and malformed output cannot be clean.

TS requires each file's effective pinned parser object, explicit single bound project/tsconfigRootDir, enabled actual pinned typed-rule object through its plugin alias, and Program/source/checker/maps/config identity observed during traversal. No projectService, injected programs or syntax-only fallback. Missing/suppressed observation or mixed typed/untyped scope fails. Inline suppressions remain disclosed policy; lint is not tsc or complete correctness.

One managed helper owns metadata/analyzer children. Node compile cache is disabled; ESLint uses fix:false/cache:false and an invocation-owned unused cache location; Ruff forces no-fix/no-fix-only/no-cache/force-exclude. Host publication selects exact UUID work artifacts request.json, native.json, findings.json, metadata.json, report.md. Native and normalized findings retain full supported detail. Bounded reports disclose omitted counts and full mutable artifact references, never a lossless/native-output or product-acceptance claim. Limits are2000 selected files, 10000 visited source entries,16MiB complete helper transport,32MiB per complete artifact and48000-byte report display. Full-resource overflow fails, not truncates. Observed Git HEAD/dirty status, config/tsconfig/root lock hashes and scope metadata do not freeze inputs or certify native-config dependency closure. Non-Git is valid.

Optional observed source inputs ​

src/retrieval/collection-definitions.ts owns two strict version1 JSON contracts. .saivage/config/observed-collections.json has type observed-collections and collections (0–32 entries). Each has unique name [a-z][a-z0-9-]{0,63}, purpose (1–1024 UTF-8 bytes), kind documentation|code, project-relative directory (1–512 bytes), include (1–64 patterns) and exclude (0–64 patterns). Skills are documentation. Literal components allow letters, digits, underscore, dot, space and @+,-; patterns also allow component * and whole-component **. Empty, dot/parent components, absolute roots, negation and regex syntax are rejected; directory . denotes project root. Patterns are case-sensitive; exclusions win. Absent definitions disable retrieval; malformed present inputs fail their consumer. No hot reload. Reset preserves these operator inputs.

Private .saivage/config/observed-collections-native.json has type xerj-observed-deployment: endpoint http://127.0.0.1:<port>, native {source,executable,sha256}, model {revision,directory,mode,dimensions,files}, roots [{directory,prefix}]. Exact source/build/model values are schema-selected; prefixes are unique sv- plus32 lowercase hex digits. Roots are canonical project-relative identities. No concrete destinations, mapping/copy-pipeline schema, token, progress or capability cache. Unsupported versions/unknown fields fail. Descriptor and fixed .saivage/config/xerj.key are refused by Files, including resolved aliases before body reads. The raw key allows nonblank opaque text≤4096 UTF-8 bytes total, one optional final newline, no embedded whitespace/ controls. Failures do not expose content; rotation requires adoption/client restart.

See prepare/adopt for exact dependency paths, CLI, generated units and uneven native embedding limits.

Lookup for the current source contract, not a supported-version matrix or a second behavior specification. For tasks and coordinated examples use Configure an instance. For existing-state changes use state adoption. All objects below are strict: unknown keys are rejected, not ignored. “Required” means no source-schema default; bundled template values are listed separately from defaults.

Owners and selected input ​

ConcernActual owner
YAML shape and defaultssaivageConfigSchema
Selected file, decode, effective type map and publicationResolvedConfigAuthority
Environment expansion/exceptionsinterpolateValue
Cross-field semantics, prompts, graph, tool scopecompileProjectWorkflows
Candidate capabilities/model resolutionProvider, capability merge
Live model/tool capacity bindingbindRuntimeWorkflows in the workflow compiler
Startup selectionloadEnvironment, parseCommand, Analyst startup

Default path is <project>/.saivage/saivage.yaml. Ordinary string values expand ${ENV_VAR} from the captured startup environment. Missing variables substitute empty strings and, after successful loading, produce redacted advisory warnings without values. Keys are not expansion hosts. Record initializer template and action execution config/inputs and durable prompt compaction_key values remain literal. The latter exception applies to lifecycle entry, correction, record, direct/conditional route and pending-notification declarations, not arbitrary fields sharing that name. Prompt references still expand normally. Dynamic MCP connection values are also literal, independently of YAML.

The source schema decodes first; an omitted card_types gets the complete classic map; the effective schema and workflow compiler then validate it. There is no partial-map merge. Reconfigure publishes validated next-start YAML and reports restart required; it does not hot-load workflows/prompts.

Command-specific input selection ​

CommandProject rootYAML / control authority
start--project-root → SAIVAGE_PROJECT_ROOT → cwd, canonicalized--config → SAIVAGE_CONFIG → selected root's .saivage/saivage.yaml
init, reset, repairExact cwd, canonicalized; no ancestor searchThat root's .saivage/saivage.yaml, with the invoking process's interpolation environment; Start root/config selectors do not apply
status, pause, resume, stop, restart_server, gc-workNearest ancestor of cwd, including cwd, containing .saivage/saivage.yaml (findProjectRoot)Only the selected project's verified live lock endpoint/auth; never endpoint rediscovery from YAML, flags, environment or defaults

Offline commands do not accept --project-root or --config. Init alone may materialize an absent canonical YAML from its selected profile. Identical YAML text does not establish identical effective inputs when interpolation environments or prompt closure differ. Before consequential retained-input operations, follow the offline input gate. Control commands retain their five-way ownership outcomes, not offline runtime-state access.

Top-level YAML ​

Explicit work GC inputs ​

saivage gc-work [--before <timestamp>] [--target-bytes <bytes>] [--dry-run | --delete] has no YAML settings, scheduler or startup/environment aliases for its filters. Default and explicit dry-run select API mode dry_run; --delete selects delete. Both flags together are rejected before delegation. before is RFC3339 with an explicit zone and means mtime strictly earlier; target_bytes is an optional nonnegative safe integer for best-effort accounted logical bytes remaining. The strict POST /api/runtime/gc-work body requires mode, accepts only those two optional fields and rejects unknown keys. Operator-session authentication applies; CLI bearer delegation uses SAIVAGE_API_TOKEN only when the live lock publishes bearer mode. Missing/dead/unverifiable owners or null endpoints refuse without fallback. This is not an offline command. Follow the preview-first procedure; each delete computes a new selection.

YAML keys ​

KeyRequired/defaultContents
agentsRequiredMap of named declarations; agents
analyst_agentRequiredExisting global agent name
oversightRequiredEnabled policy, distinct global agent and interval; Oversight
modelsRequiredRoutes plus profile/equivalence/failover expansion
providers{}Provider map; empty may parse but cannot supply required runtime candidates
server{port: 8080, host: '0.0.0.0'}Bind defaults, overridable by startup inputs
compactionRequiredEnabled literal true, fractions and fixed summarizer
card_typesOptional in sourceOmission selects complete classic types; required in effective config
mcpServersOptionalOutbound server entries; not inbound Analyst settings

No top-level legacy role-model keys, analyst_mode, token field, absolute context budget or arbitrary plugin-install declaration exists.

Identifier vocabulary ​

Agent, card-type, route/profile, prompt reference and compiled node identifiers start with a lowercase letter, then up to63 lowercase letters/digits/hyphens. Outcome IDs additionally allow underscore. Tool names use lowercase letters/digits/ underscore, letter first,≤64. Record names are a letter-led lowercase letters/digits/hyphens stem≤64 followed by .md, with no directories. record_writes patterns allow * within that stem (including at its start). Record schema labels use the same letter-led stem followed by .v and a positive decimal version. These labels are not runtime migration instructions.

Owners: agent, card type, record and the configuration/compiler schemas.

Providers and accounts ​

Path providers.<provider>, source providerEntrySchema:

FieldDefault/constraintMeaning
priorityOptional integer; runtime50Lower provider priority selected first
modelsOptional string array; runtime emptyModel IDs this provider offers
apiKeyOptional stringCredential; prefer environment substitution/private input
baseUrlOptional stringProtocol endpoint override, not a universal URL default
authProfileOptional stringStored auth-profile reference
capabilitiesOptional objectProvider-level declarations below
modelCapabilitiesOptional map model→capability objectHighest-priority capability overrides
accountsOptional map name→accountExplicit candidate credentials/configuration

Each account accepts only priority (integer, runtime100), apiKey, baseUrl, authProfile, models and capabilities. Omitted account models inherit provider model eligibility. Provider must list the model. Eligible explicit accounts are ordered lower-priority first; when none serves it, the provider's implicit account can serve it from provider settings. With no explicit accounts the implicit account is used. Its candidate account is null; named candidates carry the account name. Model routes do not select a named account; the fixed summarizer candidate can.

Capability object ​

All fields are optional overrides, not universal service facts:

FieldAccepted values / constraintGlobal resolution default
transportProtocolopenai-chat-completions, openai-responses, openai-codex-backendopenai-chat-completions
toolsModenative, unsupportednative
imageInputBooleanfalse
exclusiveToolChoiceSupportnative, parallel_off, unsupportednative
responsesReasoningStrict object with optional effort: minimal/low/medium/highAbsent
contextWindowTokensPositive integerNo global numeric default
maxOutputTokensPositive integerNo global numeric default
quirksString array[]

Resolution is model override→account→provider→built-in model/provider→global. Built-in openai-codex uses Codex transport, parallel_off and its named quirk; github-copilot supplies its auth-profile quirk. Exact models gpt-6.1-sol and gpt-6-astra get built-in image support, but their Chat transport tool mode is unsupported. Image requirements reject Chat even if imageInput: true. Local declarations do not certify remote behavior or credential validity.

Use the coherent provider/routes/summary excerpt instead of copying one capability row as a provider recipe. Secret-bearing auth profiles are separate inputs, not a YAML object to paste into docs or logs.

Models and route expansion ​

PathRequired/defaultConstraint
models.routesRequired mapNamed route declarations
routes.<name>.candidatesOne of candidates/profileNonempty list of nonempty IDs; compiler rejects duplicate route candidates
routes.<name>.profileOne of candidates/profileExisting named profile with nonempty resolved model list
routes.<name>.temperatureRequiredNumber0..2
routes.<name>.max_tokensRequiredPositive integer; candidate capacity must support request
models.profiles{}Name→strict {preferred, allowed}
profiles.<name>.preferred / .allowedEach []Ordered string lists; compiler checks duplicates for referenced profiles
models.equivalents[]Array of model-ID arrays
models.failover{}Model→ordered nonempty-string array; compiler rejects unknown/duplicate references

Expansion takes explicit candidates, or profile preferred then allowed. For each model: add that model, then other IDs in its first matching equivalence group, then its configured failover list. Keep the first occurrence of each ID. Each ID resolves across providers/accounts by their priorities. This is candidate ordering, not a promise of failover for every failure class; see provider failure classification. Saivage does not compact merely to fit a small fallback model.

Profile-route excerpt (assumes these IDs have provider declarations):

yaml
models:
  routes:
    planner: { profile: planning, temperature: 0.7, max_tokens: 4096 }
  profiles:
    planning: { preferred: [large-model], allowed: [other-model] }
  equivalents: []
  failover: {}

This is not the five-route replacement used by the bundled catalog; use the guide's coordinated example for that task.

Agents ​

Path agents.<name>; all fields required except the inner prompt default:

FieldType / constraint
promptStatic prompt declaration below
toolsExact ordered array of canonical scope-valid tool names; no duplicates
model_routeExisting route identifier
skillsBoolean; must equal whether skill is selected
sessionglobal or card
can_create_childrenBoolean; create_card requires true
record_writesUnique lowercase .md name/pattern array, with * wildcard support

The configured analyst_agent must be global. Card nodes/notification recipients must be card-scoped. Only configured Analyst/Oversight globals may select public queue_notification. Tools are compiled from actual binders, not inferred from agent labels. The shipped inventory is the precise tool lookup, not this field table.

Prompt declarations ​

DeclarationFieldsDefault/constraint
Static: agent role, agent-node taskreference, compactableReference required; compactable defaults true
Durable: correction, entry, edge, pending-notification or record promptreference, compactable, optional compaction_keycompactable true; a nonempty key is allowed only with compactable false

Under workflow5, a key remains the exact parsed YAML string, not quote delimiters or escape spelling. ${POLICY_KEY}, embedded substitutions, whitespace, case and Unicode remain literal whether variables exist or not; no key-only missing-variable warning is emitted. Empty is invalid; whitespace-only is nonempty and is not trimmed. Static declarations still forbid keys. Body rendering and fragment inclusion do not transform key identity. See protection semantics and workflow adoption.

References select .md files by the actual override tiers, not by agent name alone. Globals use shared hosts; card hosts select project-card/shared then bundled card/shared tiers in root-major order. One-level fragments and host-specific tokens are compiled. Card-workflow agent role templates use the workflow-agent host, which requires exactly one contractDescription placeholder after fragment expansion. Node task and other process templates use the process host: they accept cardType, not contractDescription. Record-context and initializer hosts have their own tokens and counts. Complete host table and selection rules: prompt compiler contract.

Oversight ​

All fields required; bundled values are enabled: true, agent: oversight, interval_seconds: 7200 (template choices, not source-schema defaults).

FieldConstraint
enabledBoolean; disabled policy still compiles
agentExisting global agent distinct from Analyst; no child creation, record writes or skills; restricted read-only/notification tool inventory
interval_secondsPositive number whose milliseconds are finite and positive; not restricted to integers

The running epoch/cadence is process-local. First check waits a full continuous eligible interval; no persisted due-time queue. See the complete schedule and lifecycle.

Compaction ​

Path compaction; source compactionSectionSchema:

FieldRequired/defaultConstraint
enabledRequiredLiteral true; disabling is not a current option
context_utilization_fraction0.8>0 and≤1
trigger_fraction0.9>0 and≤1
tail_fraction0.250..1 and≤trigger_fraction
snapkeep_straddler_verbatimOr compact_straddler
summarizer_candidateRequiredStrict {provider, account, model}; provider/model nonempty strings, account nonempty string or explicit null

Usable input is candidate-specific, subtracting requested output after utilization; binding freezes positive eligible capacities. Tail is a target of that usable input, not guaranteed verbatim retention. The fixed summary candidate must resolve and support its2000-token output request and relevant image capability. Full arithmetic/whole-round snapping/atomic constraints and failures are owned by capacity and accounting and the provider-context specification. These fractions do not cap cost or ensure a request fits.

Card types, records and workflow ​

Path card_types.<type>; project required in a supplied map:

FieldConstraint
permitted_child_typesRequired array; configured unique types, never project; empty means leaf
recordsRequired name→record declaration map; exactly one bootstrap record
workflowRequired workflow5 object below

At resulting card depth12 creation requires a compiled leaf type. Child permission and card identity are runtime requirements, not configurable allocation scans.

Record declarations and initialization ​

FieldRequired/defaultConstraint
formatRequiredLiteral markdown
schemaRequiredLabel such as work-status.v1
bootstrapRequiredBoolean; exactly one true per type
initializationOptional or nullStrict {format_version: 1, template: nonblank-string}; bootstrap initialization forbidden

Initializer text allows cardType/cardId/cardTitle/nodeId/recordName tokens and direct fragment includes. It is literal data, not environment expansion or a prompt grant. Node selection and exact write permission are separate. See the coordinated initializer example and baseline0/draft/accepted semantics.

Workflow object ​

FieldRequired/defaultConstraint
format_versionRequiredLiteral4, independent of operation/initializer versions
notification_recipientRequiredExisting card agent used by a workflow node
entriesRequiredExactly BACKLOG, CHANGED, BLOCKED, STOPPED
entries.<entry>.nodeRequiredExisting node; compiler validates identifier
entries.<entry>.promptOptional except required STOPPEDDurable declaration; cannot target action
nodesRequiredNonempty node map; all reachable from entries and with a path to terminal
after_activation_commitOptionalStrict {statuses, execution}; unique nonempty subset done/blocked/failed and action execution

STOPPED must target the notification recipient's agent node. Nonrecipient DONE edges require a pending-notification route to that recipient; recipient DONE edges cannot declare it. Full graph semantics, including interruption and promotion, are owned by the workflow engine.

Node object ​

FieldRequired/defaultConstraint
executionRequiredDiscriminated agent/action below
output_recordOptionalDeclared own nonbootstrap record; output-declaring action only, requires exactly continue/updated
initialize_recordsOptional unique ordered record listAgent only; each declared initializer, matching write pattern and direct write tool
record_promptsOptional arrayAgent only; each strict {record, selection, presence, prompt}
record_prompts[].selectionRequiredaccepted/effective
record_prompts[].presenceRequiredrequired/optional
record_prompts[].promptRequiredDurable record-context host declaration
records{}Name→strict {mode: clean|continue, gate: exists|updated}
descendant_contextOptionalAgent only; strict {records: record-name-array, require_unchanged_until_accept: boolean}
edgesRequired nonempty mapOutcome→direct or conditional edge

Agent record requirements must match record-write authority; clean/updated needs write. Apart from its bound stdout record, action requirements are accepted-only continue/exists; actions cannot initialize/clean/close records. Conditional record prompts are fresh same-read observations, not immutable requirement text inferred from a descriptor. See same-read record supplier.

Agent and action execution ​

Agent execution fieldRequired/default
kindLiteral agent
agentExisting card-scoped agent
promptStatic process-host declaration for the node task
correction_promptDurable declaration
data_inputsOptional name→flat data-field declarations
inputsOptional name→literal/factual binding
Action execution fieldRequired/default
kindLiteral action
actionExact compiled operation ID, e.g. shell.run
contract_versionLiteral1
configRequired; selected operation's strict schema
inputsRequired map, including explicit args supplier for shell.run

No model, prompt or session is selected by an action. Operation IDs use exactly two dot-separated components, each letter-led lowercase letters/digits/hyphens≤48. Trusted plugin declarations are explicitly compiled modules, not a YAML-installed service. Reserved shell/git/saivage namespaces do not imply operations exist. Owner: operation contracts.

shell.run config ​

Owner: shellOperationConfigSchema.

FieldRequired/defaultConstraint
scriptRequiredNonblank safe literal≤4096UTF-8 bytes; Bash with pipefail, no implicit set-e
cwd.Exact project-relative path; no absolute, empty, dot or dotdot components (except sole .)
env{}Shell variable name→safe literal≤4096bytes; no secret keys or PROJECT_ROOT/SAIVAGE_ROOT overrides
timeout_ms120000Integer1..600000
terminate_grace_ms2000Integer0..10000
artifacts[]≤16 unique exact relative paths, no globs

Required input args is strings. Outcomes are exactly passed(exit_code0), failed(exit_code≥1), signalled(signal string), timed_out(reason string). Every outcome needs a route. output_record is on the node, not in this config or hook. See the action example.

Typed inputs and routes ​

Owner: operation-routing.ts. Flat fields are string (optional enum), integer (optional safe min/max), boolean or strings. Field names are letter-led lowercase letters/digits/underscore≤48; max32 fields,≤4096UTF-8 bytes/string,≤256 list elements,≤64KiB encoded values. No nested objects, defaults, coercion or expression evaluator. Private operation fields cannot route, feed another node or be retained as public observations.

ShapeFields / constraints
Base input bindingExactly {literal: string|boolean|safe-integer|string[]} or {source: card_id|card_type|card_title|committed_status}; committed_status hook-only
Direct routeRequired target, optional durable prompt, pending_notifications and inputs
Node targetExactly {node: identifier}
Terminal targetExactly {terminal: DONE|BLOCKED|FAILED, promote: current|{latest_node: identifier}, export_records: record-name-array}
pending_notificationsExactly {node, prompt}; recipient agent recovery alternative on nonrecipient DONE only
Route inputsDestination field→{output: predecessor-field}; terminal routes cannot bind inputs
Conditional edge{cases: [...], otherwise: direct-route}; action only,1..8 cases
Each caseDirect-route fields plus required unique id and when: {field, op, value}
wheneq (typed scalar equality), gt/gte/lt/lte (integer only); scalar value string/boolean/safe-integer

First matching case wins after full operation-return validation. All incoming routes/lifecycle entries/pending re-entry must supply every destination input exactly once, with compatible bounds. Agent predecessor outputs are not invented. Promotion by latest_node must name a real reachable predecessor; export and record context closure is compiler-checked. Agent prompts cannot target actions.

Typed handoff excerpt, assuming a declared compatible integer output count and destination input findings:

yaml
# On an action outcome route:
target: { node: assess }
inputs: { findings: { output: count } }
# In assess.execution:
# data_inputs: { findings: { type: integer, min: 0, max: 1000 } }

This does not claim shell.run returns count; it demonstrates the binding shape for an explicitly compiled operation declaring that field. Nonempty selected agent entry data is delivered once as quoted compactable facts, not tool/write authority.

Outbound MCP YAML ​

Path mcpServers.<name>; two disjoint strict shapes:

Fieldstdiostreamable-http
transportRequired literal stdioRequired literal streamable-http
commandRequired nonempty stringNot accepted
argsOptional string arrayNot accepted
envOptional string→string mapNot accepted
urlNot acceptedRequired absolute HTTP(S) URL
disabledfalsefalse
autostarttruetrue

YAML connections use normal interpolation. Dynamic .saivage/config/mcp-servers.json definitions use connection-only fields, remain literal and never autostart; they cannot collide with YAML names. Transport config, tool grants, live binding and discovered catalog are distinct. Definition edits do not hot-rebind the whole runtime. Full example and operations: outbound MCP.

Server YAML ​

server.host is a string default 0.0.0.0; server.port is a positive integer default8080. YAML does not admit0 and does not itself impose the CLI65535 upper bound. Do not advertise wildcard binding without deployment-owned confinement. Actual listener parsing/binding is a separate startup boundary; port0 is available only through startup CLI/env. There are no YAML operator-token, inbound Analyst or private failed-request-capture fields.

Startup-only CLI and environment ​

These are not YAML keys. start singleton options reject duplicates; other commands do not inherit start flags. Runtime-control CLI commands use only the verified live lock's published endpoint/auth, not these startup inputs.

SelectionPrecedence/default or constraint
Project--project-root→SAIVAGE_PROJECT_ROOT→cwd; canonical existing root
Config--config→SAIVAGE_CONFIG→project/.saivage/saivage.yaml
Host--host→SAIVAGE_HOST→server.host
Port--port→SAIVAGE_PORT→server.port; CLI/env integer0..65535, selected raw input validated without fallback
--create-runtimeExplicit initial-runtime publication option, not repair/reset
SAIVAGE_API_TOKENUnset disables operator auth; blank/padded fails; never a URL token
NODE_ENVproduction default; development/production/test
LOG_LEVELinfo default; fatal/error/warn/info/debug/trace/silent
--failed-provider-diagnostics UUIDCLI-only, off by default; sensitive bounded private capture, not a persisted setting/environment alias

Failed-request capture consequences/retention are in private failed-request captures. Bind/auth/service setup is in deployment. The browser has no token login; use private browser credential setup. Credential environment is not automatically passed to child commands; the command allowlist owns that separate contract.

Inbound Analyst startup selection ​

InputDefault/constraint
--analyst-modeinternal default; internal/external/both
--analyst-mcp-portRequired external/both; decimal integer1..65535
--analyst-mcp-principalRequired external/both; letter-led lowercase letters/digits/hyphens≤64; credential-holder label, not verified identity
--analyst-mcp-toolsRequired nonempty unique comma-separated exact subset of configured Analyst canonical tools; no wildcard/role inference
SAIVAGE_ANALYST_MCP_TOKENRequired external/both, nonblank/unpadded, different from operator REST token

There are no mode/port/principal/tools environment aliases. Internal mode rejects unused external settings/token. Selected startup settings are immutable. External-only disables internal submissions before ingress/provider, not internal history inspection. Both exposes concurrent operations, not shared chat/lease.

The listener is 127.0.0.1 at a project-digest-bound path announced on startup; do not construct a guessed URL. The full inbound procedure owns protocol2025-11-25, initialize/context/discovery, mandatory JSON+event-stream Accept/header requirements, separate bearer, no Origin/query/session/batch/GET stream, and calls surviving disconnect. Project Stop does not close this application-owned listener.

What lookup does not establish ​

Schema acceptance is not workflow compilation, runtime capability binding, whole retained-history compatibility, remote credential validation or provider delivery. Read participating identity changes before replacing installed maps, and durable source evidence when comparing releases. This reference performs no conversion or live adoption.