Configuration

Complete reference for every top-level key in your praxec YAML config.

Your entire gateway is one YAML file (or a few, if you split it up). Here’s every top-level key you can set and what it does.

Minimal config

version: "1.0.0"
proxy:
  expose:
    - name: hello.echo
      executor: { kind: noop }

That’s a valid config. Everything except version is optional. You add keys as you need them.

version

Required, non-empty string.

version: "1.0.0"

"1.0.0" is the current convention. The value isn’t parsed as semver or checked against a fixed list – any non-empty string is accepted – but it gives the gateway a hook to detect and migrate config formats as the schema evolves.

include

Merge other YAML files into this config before the gateway starts. Maps merge (later wins on key collisions), arrays concatenate.

include:
  - ./connections.yaml
  - ./workflows/deploy.yaml
  - ./workflows/review.yaml

Paths are relative to the main config file. This is useful for splitting a large config across teams or environments – keep shared connections in one file, team-specific workflows in another.

An entry can also be an object { uri, hash } for remote or verified includes:

include:
  - ./connections.yaml
  - { uri: "file:///etc/praxec/shared.yaml" }
  - { uri: "https://example.com/policy.yaml", hash: "sha256:..." }

Supported schemes are file://, https://, and git+https://. Any non-file:// URI requires a hash (sha256) so the merged config is reproducible and tamper-evident; the gateway refuses to merge if the fetched body doesn’t match.

repos

Pull in versioned resource repos – shared collections of capabilities, orchestrators, skills, and scripts that live in their own directory with a praxec.repo.yaml manifest at the root. This is the primary composition mechanism: instead of copying definitions between configs, you reference a repo and its definitions are merged into your gateway registry at load time.

repos:
  - path: ~/repos/cognitive-architectures
  - path: ../praxec-meta

Each entry is an object with a path field pointing at the repo directory. Relative paths resolve against the host config’s directory (the same convention as include:), and a leading ~/ expands to your home directory.

Every definition loaded from a repo is namespace-prefixed with the repo’s declared namespace – a repo whose manifest declares namespace: cognitive surfaces its ids as cognitive/<id> (e.g. cognitive/flow.add-feature). Two declared repos that share a namespace fail at config load (DUPLICATE_REPO_NAMESPACE).

The repo’s praxec.repo.yaml manifest must declare schema: praxec.repo/v1, a name, a namespace, and a version, plus an optional layout mapping the directories where each tier lives (defaults: capabilities/, orchestrators/, skills/, scripts/, connections/).

overrides

When a repo provides a definition and your host config defines an id that collides with it, you must explicitly acknowledge the shadowing by listing the fully-qualified id in the top-level overrides: array. This closes a supply-chain backdoor: an operator can’t silently shadow a vendored definition.

overrides:
  - cognitive/cap.plan.vet

overrides: is an array of fully-qualified (namespace-prefixed) id strings. With the override declared, your host definition wins the collision. The gateway errors if you shadow a repo-provided id without listing it (ANONYMOUS_OVERRIDE), or if you list an id that no declared repo actually provides (STALE_OVERRIDE).

capabilities

Named, reusable capability definitions. You define a capability once here, then reference it from proxy.expose or from workflow transition executors.

capabilities:
  github.list_issues:
    title: List GitHub issues
    description: List issues from a GitHub repository.
    tags: [github, issues]
    inputSchema:
      type: object
      required: [repo]
      properties:
        repo: { type: string }
      additionalProperties: false
    executor:
      kind: mcp
      connection: github
      tool: list_issues
    guards:
      - { kind: role, role: developer }
    reliability:
      timeoutMs: 30000
      retry:
        maxAttempts: 2
        backoff: fixed
        initialDelayMs: 1000

You can also wrap another capability to add guards or reliability on top:

capabilities:
  github.list_issues.safe:
    wraps: github.list_issues
    guards:
      - { kind: permission, permission: github.read }

The wrapper inherits the wrapped capability’s executor and stacks its own guards and reliability on top.

connections

Named MCP server connections. The gateway speaks to these at runtime. Three kinds:

MCP connection (stdio)

connections:
  github:
    kind: mcp
    command: github-mcp-server
    args: []
    env:
      GITHUB_TOKEN: "${GITHUB_TOKEN}"

The gateway launches this as a child process and speaks MCP over stdio. Works with any MCP server – native binaries, npx shims, uvx launchers, Docker containers.

connections:
  filesystem:
    kind: mcp
    command: npx
    args: [-y, "@modelcontextprotocol/server-filesystem", "/tmp"]

MCP connection (HTTP)

If you provide url instead of command, the gateway connects to a running MCP server over the Streamable HTTP transport:

connections:
  remote_server:
    kind: mcp
    url: https://mcp.example.com/mcp

When both url and command are set, url wins – a URL implies a hosted server rather than a process to launch.

CLI connection

connections:
  dotnet:
    kind: cli
    command: dotnet
    workingDirectory: /path/to/project
    env:
      DOTNET_ENV: production

Used with the cli executor. The gateway runs shell commands through this connection.

REST connection

connections:
  payroll:
    kind: rest
    baseUrl: https://payroll.example.com
    headers:
      Authorization: "Bearer ${PAYROLL_TOKEN}"

Used with the rest executor. Headers defined here apply to every request through this connection.

proxy

The proxy section defines what capabilities the gateway exposes to the model. Two mechanisms: expose (define inline or reference capabilities) and import (auto-import from MCP connections).

proxy.expose

Each entry is either an inline definition or a reference to a named capability.

Inline definition – you define everything right here:

proxy:
  expose:
    - name: github.list_issues
      title: List GitHub issues
      description: List issues from a GitHub repository.
      tags: [github, issues, read]
      aliases: [gh-issues, list-issues]
      examples:
        - "List all open issues in the main repo"
      inputSchema:
        type: object
        required: [repo]
        properties:
          repo: { type: string }
        additionalProperties: false
      executor:
        kind: mcp
        connection: github
        tool: list_issues
      guards:
        - { kind: role, role: developer }
      reliability:
        timeoutMs: 30000

Capability reference – point to a named capability:

proxy:
  expose:
    - capability: github.list_issues
      as: issues.list          # optional: rename for the proxy
      description: Override description if you want
      tags: [extra-tag]        # merged with the capability's tags
      aliases: [find-issues]   # search synonyms
      guards:                  # stacked on top of the capability's guards
        - { kind: permission, permission: repo.read }

proxy.import

Auto-import tools from a connected MCP server. The gateway calls tools/list on the connection at startup and creates a proxy exposure for each tool.

proxy:
  import:
    - connection: github
      prefix: github           # tools become github.list_issues, github.create_issue, etc.
      include: [list_issues, create_issue]  # only these tools (omit for all)
      exclude: [delete_repo]               # skip these tools
      tags: [github, source-control]       # applied to all imported tools

You can mix imports with explicit declarations. Declared capabilities can carry guards and reliability that imports don’t have by default.

workflows

Multi-state workflow definitions. Each workflow is a state machine with states, transitions, guards, and executors.

workflows:
  deploy_pipeline:
    description: Lint, test, build, and deploy a service.
    tags: [deploy, pipeline]
    aliases: [ship, release]
    examples:
      - "Deploy the payments service to staging"

    inputSchema:
      type: object
      required: [service]
      properties:
        service: { type: string }
        environment:
          type: string
          enum: [staging, production]
          default: staging
      additionalProperties: false

    initialState: lint
    initialContext:              # seed values for workflow context
      attempts: 0
    maxChainDepth: 10           # max deterministic transitions before halting (default: 50)
    timeoutMs: 3600000          # workflow-level timeout (1 hour)
    linkFilter: all             # "all" or "byGuards" — controls which transitions appear as links

    onTimeout:                  # what happens if the workflow times out
      target: failed
      executor:
        kind: mcp
        connection: notifier
        tool: send_alert

    states:
      lint:
        goal: Validate code quality
        guidance: This step runs automatically.
        transitions:
          run_lint:
            title: Run linter
            target: test
            actor: deterministic          # runs automatically, no model decision
            executor:
              kind: cli
              command: lint-check
              args: ["$.input.service"]
            output:
              lintPassed: "$.output.json.passed"

      test:
        transitions:
          run_tests:
            title: Run test suite
            target: ready_to_deploy
            actor: deterministic
            executor:
              kind: cli
              command: test-runner
            output:
              testsPassed: "$.output.json.passed"

      ready_to_deploy:
        linkFilter: byGuards    # per-state override — only show transitions whose guards pass
        transitions:
          deploy:
            title: Deploy to environment
            target: deployed
            actor: agent
            guards:
              - { kind: expr, expr: "$.context.testsPassed == true" }
            executor:
              kind: cli
              command: deploy
              args: ["$.context.artifactId"]
            output:
              deploymentId: "$.output.json.deploymentId"
            reliability:
              timeoutMs: 60000
              retry:
                maxAttempts: 3
                backoff: exponential
                initialDelayMs: 2000

          abort:
            title: Abort deployment
            target: aborted

      deployed:
        terminal: true

      aborted:
        terminal: true

      failed:
        terminal: true

Transition details

Each transition supports:

Key Purpose
target Destination state (required)
title Human-readable name, shown in links
description Longer explanation
actor Who can trigger: agent, human, system, deterministic (default: agent)
inputSchema JSON Schema for transition arguments
guards Array of guards that must all pass
executor What runs when the transition fires (see executors)
output Maps executor output into workflow context
evidence Requires specific evidence artifacts
reliability Timeout, retry, and fallback policies
prefill Pre-resolved argument values for links, reducing what the model has to generate
branches Auto-branch destination based on executor result (first matching when guard wins, otherwise falls back to target)

Actor types

Actor Behavior
agent Default. The model decides when to take this transition.
human Only a human principal can submit. The gateway rejects agent submissions with ACTOR_MISMATCH.
system Reserved for system-triggered transitions.
deterministic The runtime chains through this automatically – no model decision needed. Multiple deterministic transitions execute in a single round trip.

audit

Controls where audit events go. Every workflow action emits structured JSON events automatically.

audit:
  sink: stderr           # stderr | file | memory | none
  path: ./audit-logs     # required when sink is "file" — a DIRECTORY
  rotation: daily        # hourly | daily | weekly (default: daily)

When sink: file, path is a directory of date-rotated log files, not a single .jsonl. The rotation key controls how often a new file is started (hourly, daily, or weekly); it defaults to daily.

See audit events for the full event reference.

discovery

Controls what gets indexed for search.

discovery:
  include:              # what to index (default: ["proxy", "workflows"])
    - proxy             # proxy capabilities (default: included)
    - workflows         # workflow definitions (default: included)
    - connections       # raw connections (default: not included)

include is the only honored key. By default, proxy capabilities and workflows are indexed. Add connections if you want raw connections to appear in search results too. An unrecognized token (e.g. workflow instead of workflows) fails the config with INVALID_DISCOVERY_INCLUDE rather than silently dropping a category.

store

Where workflow instances are persisted. See stores for the full reference.

store:
  kind: memory                 # memory | file | sqlite
  path: ./workflows.db         # filesystem path — used by file and sqlite

path is the filesystem location for file (a directory) and sqlite (a database file); memory ignores it. Only sqlite keeps Evidence and acknowledgment stores durable. A serve deployment refuses kind: file (it would lose governance state on restart) unless gateway.allow_ephemeral: true is set for dev.

embeddings

Optional. Enables semantic candidate ranking for lexicon SUBJECT_NEEDS_DEFINITION interactions (SPEC §30.10.10). Omit the block entirely (or set backend: none) to use lexical-only ranking.

embeddings:
  backend: ollama                            # none (default) | ollama | openai_compatible
  url: http://localhost:11434/api/embeddings # required when backend != none
  model: nomic-embed-text                    # provider's model name
  dimensions: 768                            # required (>0) when backend != none
  api_key_env: OPENROUTER_API_KEY            # optional; absent for unauthenticated local services

When a backend other than none is set, the gateway POSTs to the configured URL at lexicon-write time to compute embeddings, and at SUBJECT_NEEDS_DEFINITION time to rank candidates semantically. ollama and openai_compatible select the request/response format. On backend failure, lexicon writes are rejected with EMBEDDING_BACKEND_FAILED. See Lexicon and Discovery for the tiered ranking details.