Polycallfile reference

Polycallfile (exactly that capitalization, no extension) is the single, explicit source of runtime topology and policy (CFG-001). There is no include mechanism, no parent-directory search, no home-directory discovery, and no environment-variable override of its contents. The CLI selects ./Polycallfile when no path is given, or an explicit final positional argument otherwise.

Not this project's Polycallfile, despite the name

docs/CONFIGURATION_STANDARD.md and the project's original README describe an older, unrelated three-layer scheme (Polycallfile + Polycallrc + Polycallrc.<language>, bare server LANG PORT:PORT lines, config rc show/config rc validate commands). None of that matches the current grammar, and none of those extra commands exist in the current CLI reference. It is preserved as historical material in the migration guide; this page documents the schema main actually parses.

Grammar

A small, deliberately restricted, TOML-like declarative syntax (CFG-004):

file       = { line } ;
line       = ws, [ section | assignment ], ws, [ comment ], newline ;
section    = "[", identifier, { ".", identifier }, "]" ;
assignment = identifier, ws, "=", ws, value ;
value      = string | integer | boolean | array ;
array      = "[", ws, [ scalar, { ws, ",", ws, scalar } ], ws, "]" ;
identifier = letter, { letter | digit | "_" | "-" } ;

Identifiers are ASCII, case-sensitive. Strings are double-quoted, with only \", \\, \n, \r, \t as valid escapes. No multiline strings, no hex/float/date/null literals, no inline objects. Comments start with # outside a string. Duplicate keys, repeated sections, and unknown sections/keys are errors — there is no last-value-wins merging.

Sections and fields

Section Key Type / meaning
root schema integer, exactly 1
[runtime] name nonempty string, ≤128 UTF-8 bytes
[runtime] listen tcp://127.0.0.1:PORT or tcp://[::1]:PORT
[runtime] max_connections 1–4096, default 128
[runtime] workers 1–256, default 4
[runtime] queue_capacity 1–65536, default 1024
[runtime] max_frame_bytes 1024–16777216, default 1048576
[runtime] max_inflight_per_connection 1–1024, default 64
[runtime] call_timeout_ms 1–3600000, default 30000
[runtime] drain_timeout_ms 1–3600000, default 10000
[runtime] startup_timeout_ms 1–3600000, default 10000
[security] mode "token", "local-auto", or "mtls" — see below
[security] token_env env var name holding the secret, when mode = "token"
[security] allow_remote boolean, default false
[telemetry] enabled boolean, default true
[telemetry] include_payloads boolean, must be false in baseline
[service.ID] language one of c, python, node, lua, go, java, cobol — informational only, see below
[service.ID] mode "external" (baseline) or "spawn"
[service.ID] max_concurrency 1–1024, default 1
[method.SERVICE.METHOD] params array of type strings, positional
[method.SERVICE.METHOD] result type string
[method.SERVICE.METHOD] idempotent boolean, default false
[grant.ID] principal authenticated principal name
[grant.ID] service, methods what this grant covers
[grant.ID] actions array containing "invoke" and/or "register"

Type strings for params/result: null, bool, i32, i64, u32, u64, f64, string, bytes, or list<T> of one scalar type (no nested lists).

[service.ID].language does not gate registration — nothing stops a provider written in a different language from registering for that service's methods. It documents intent, not an enforced constraint.

security.mode

  • "token" — the baseline profile. The secret comes from the named environment variable and must be supplied out of band.
  • "local-auto" — implemented, verified, not yet written into the published LPV1-04 text (the code refers to it as CFG-021). The runtime generates a shared secret and stores it via the OS credential facility (Windows Credential Manager, or ~/.polycall-credentials/<name> on Linux); the CLI, an in-process provider, and provider.py all read the same entry automatically. This is what the shipped root Polycallfile uses, and what Your first Python call runs.
  • "mtls" — parses, but runtime start deliberately refuses to bind when it sees this mode rather than opening a plaintext socket under a label that implies certificate-based security it doesn't provide.

The shipped example

The repository root's own Polycallfile (used by every tutorial on this site):

schema = 1

[runtime]
name = "polycall-dev"
listen = "tcp://127.0.0.1:8080"
max_connections = 1000
call_timeout_ms = 5000

[security]
mode = "local-auto"
allow_remote = false

[telemetry]
enabled = true
include_payloads = false

[service.math]
language = "python"
mode = "external"
max_concurrency = 4

[method.math.add]
params = ["i64", "i64"]
result = "i64"
idempotent = true

[grant.local]
principal = "token-principal"
service = "math"
methods = ["add"]
actions = ["invoke", "register"]

(It also declares placeholder [service.node], [service.python], [service.java], [service.go] entries with no matching [method.*] — those are unused by any current tutorial.)

CLI commands that touch it

  • polycall config validate <Polycallfile> — parses and validates only; never connects to anything.
  • polycall config show --json <Polycallfile> — prints the validated effective model. This is also how provider.py obtains connection parameters (see Core concepts) — secret values never appear in this output, only variable names where applicable.
  • polycall config migrate --from <old> <new-Polycallfile> — registered, reports unsupported. No historical-format reader is implemented yet; do not depend on this to convert an old-style config.
  • polycall runtime reload — accepted by the CLI, but the server side isn't built yet; the only fields schema 1 defines as ever reloadable without a restart are telemetry.enabled and telemetry.sample_per_million.