Extends (Presets)
The extends field lets you inherit configuration from other files or remote repositories. This enables sharing common rulesets across projects and teams.
Reference Formats
Section titled “Reference Formats”runok supports three ways to specify an extends source:
Local Path
Section titled “Local Path”Reference a configuration file on the local filesystem.
extends: - ./shared/base.yml - ~/company/runok-base.ymlPath resolution rules:
~/...expands to$HOME./...and relative paths resolve from the directory containing the current config file- Absolute paths are used as-is
- Path traversal beyond the filesystem root is rejected
GitHub Shorthand
Section titled “GitHub Shorthand”Reference a configuration file in a GitHub repository using the github: prefix.
extends: - github:example-org/security-rules@main - github:example-org/security-rules # uses default branch - github:example-org/runok-presets/readonly-unix@v1 # specific file in repoFormat: github:<owner>/<repo>[/<path>][@<ref>]
The optional /<path> specifies a preset file within the repository (without .yml/.yaml extension). When omitted, runok reads runok.yml (or runok.yaml) from the repository root. When provided, runok reads <path>.yml (or <path>.yaml).
The @<ref> part is optional and can be:
- A tag (e.g.,
v1.0.0) - A branch name (e.g.,
main) - A full commit SHA (40-character hex string)
- Omitted to use the repository’s default branch
Git URL
Section titled “Git URL”Reference any Git repository by URL.
extends: - https://github.com/example-org/runok-config.gitSupports https://, http://, and git@ URLs. An optional @<ref> suffix specifies the version.
Mutable vs Immutable References
Section titled “Mutable vs Immutable References”runok distinguishes between mutable and immutable references for caching:
| Reference Type | Example | Caching Behavior |
|---|---|---|
| Commit SHA (40 hex) | github:org/repo@a1b2c3d4... | Cached permanently |
| Tag or branch | github:org/[email protected] | Cached with TTL |
| Default branch | github:org/repo | Cached with TTL |
Mutable references (tags, branches) are cached for 24 hours by default. Immutable references (commit SHAs) are cached permanently. See Environment Variables for how to configure the cache TTL.
Resolution Order
Section titled “Resolution Order”When a config file specifies extends, runok resolves presets using depth-first traversal:
- For each entry in
extends(in order), recursively load and resolve its ownextends. - Merge all resolved presets in order.
- Merge the current config on top.
This means the current file always takes the highest priority, and earlier extends entries serve as the base.
Diamond Inheritance
Section titled “Diamond Inheritance”Diamond-shaped extends (where two presets share a common ancestor) are allowed. The shared ancestor is loaded once for each path, and both copies are merged.
# a.ymlextends: - ./b.yml - ./c.yml
# b.yml extends: [./shared.yml]# c.yml extends: [./shared.yml]# This is valid — shared.yml is merged from both paths.Circular Reference Detection
Section titled “Circular Reference Detection”Circular references are detected and rejected. runok normalizes file paths before checking, so ./runok.yml and runok.yml pointing to the same file are correctly identified as circular.
The maximum extends depth is 10 levels. Exceeding this limit produces an error.
Version Guards (required_runok_version)
Section titled “Version Guards (required_runok_version)”A preset file can declare the minimum runok version it needs by setting the top-level required_runok_version field to a semver requirement expression. Preset authors should set this whenever a file depends on schema features introduced in a newer runok, so that older runok binaries refuse the preset cleanly instead of silently ignoring unknown fields or surfacing confusing parse errors.
required_runok_version: '>=0.3.0'definitions: flag_groups: field-flag: '-f|--field *'The check is enforced per file: the project runok.yml, every file pulled in via extends, and every transitively extended preset are validated independently. If any file’s requirement is not satisfied, loading fails with an error that names the exact file and the constraint.
Interaction with update-presets
Section titled “Interaction with update-presets”runok update-presets honors required_runok_version when selecting which tag to upgrade a remote preset to. Candidate tags are inspected from newest to oldest, and the newest tag whose entire preset tree (including every file it transitively extends) satisfies the current runok version is adopted. Candidates that require a newer runok are reported as a warning so that the user knows upgrading the runok binary would unlock newer preset versions.
This lets a preset repository ship schema-incompatible changes under a newer tag without breaking users still on older runok — they will stay on the previous compatible tag until they upgrade runok themselves.
Interaction with automatic refresh
Section titled “Interaction with automatic refresh”The same check also guards the background refresh that happens when a cached remote preset goes stale. A new revision fetched from the remote is only written to the cache working tree after its required_runok_version has been verified. If the new revision (or any file it extends in the same repository) is incompatible, the refresh is silently skipped and the existing cached preset is kept, so that normal runok check / runok exec operations are never broken by a preset upgrade that the current runok cannot read.
No warning is emitted in this path on purpose — warnings about “a newer tag exists” are reserved for the explicit update-presets command so that normal operations stay quiet.
Nightly builds
Section titled “Nightly builds”Nightly builds of runok (X.Y.Z-nightly+<sha>) are treated as “latest” for the purpose of this check, so any >=X.Y.Z requirement passes automatically. Upper-bounded ranges such as ">=0.2, <0.4" intentionally reject nightly builds because nightly is modeled as strictly greater than every released version.
Caching
Section titled “Caching”Remote presets are cached locally to avoid repeated network fetches.
Cache Location
Section titled “Cache Location”The cache directory is determined by:
$XDG_CACHE_HOME/runok/presets(ifXDG_CACHE_HOMEis set)$HOME/.cache/runok/presets(fallback)
Each cached preset is stored in a directory named by the SHA-256 hash of the reference string.
Cache Behavior
Section titled “Cache Behavior”| Scenario | Action |
|---|---|
| Cache hit (fresh) | Use cached data directly. |
| Cache stale | Attempt to fetch updates. If fetch fails, use stale cache. |
| Cache miss | Clone the repository. Fail if clone fails. |
Stale cache provides resilience against temporary network failures — if a fetch fails, the previously cached version is used with a warning.
Cache Metadata
Section titled “Cache Metadata”Each cached entry includes a metadata.json file tracking:
fetched_at— Unix timestamp of when the preset was fetchedis_immutable— Whether the reference is a commit SHAreference— The original reference stringresolved_sha— The resolved commit SHA (if available)
Related
Section titled “Related”- Official Presets (runok-presets) — Ready-made rule presets for common read-only commands.
- File Discovery and Merging — How configuration files are loaded and merged.
- Configuration Schema — Full reference for
runok.yml.