How Kyn Works¶
Kyn evaluates a change set against relationships you define in YAML. It does not inspect language syntax, call a hosted service, or modify files.
The evaluation pipeline¶
changed files
→ family matching
→ kin path resolution
→ rule evaluation
→ deterministic report and exit code
That small model is enough to express policies such as “when a handler changes, its existing test must be part of the same pull request.”
Change set¶
Kyn can collect changed files in four ways:
| Mode | Example | Best for |
|---|---|---|
| Automatic Git diff | kyn check |
Normal local and CI use |
| Explicit Git refs | --base origin/main --head HEAD |
Reproducible CI |
| Explicit paths | --files a.go,b.go |
Fast local testing |
| File or stdin | --files-from changed.txt, --stdin |
Existing change detectors |
Only one mode can be active. Automatic mode uses origin/main...HEAD inside
a Git repository. KYN_BASE_REF and KYN_HEAD_REF override those defaults.
Git diff mode preserves added and modified statuses plus the destination of a
detected rename. Deleted paths are currently excluded from evaluation. Rules
that use changedStatusAny should use Git input when they need added or renamed
status; explicit path lists record every supplied path as modified.
Families¶
A family describes one logical unit in the repository. This frontend family makes component source files the entry point:
families:
- id: web-component
groups:
source:
include:
- "src/**/*.component.ts"
- "src/**/*.component.html"
baseName:
stripSuffixes: [".component"]
kin:
story: "{dir}/{base}.stories.ts"
For src/button/button.component.ts, Kyn derives:
- directory:
src/button - name:
button.component - base after suffix stripping:
button - family instance:
src/button/button storykin:src/button/button.stories.ts
Paths are slash-normalized on every operating system.
Kin¶
Kin are named related paths. Templates can use:
| Variable | Meaning |
|---|---|
{dir} |
Directory containing the matched source |
{file} |
Full matched source path |
{name} |
Filename without its final extension |
{base} |
Name after configured suffix stripping |
{ext} |
Final extension, including the dot |
Kin do not have to exist. A rule can apply only when kin exists, require it to exist, require it to change, or require it to remain unchanged.
Rules¶
A v2 rule has three parts:
- id: story-sync
family: web-component
severity: error
if:
changedAny: [source]
kinExists: [story]
assert:
kinChanged: [story]
message: "Component changed but story did not."
ifdecides whether the rule applies.assertdecides whether the applicable rule passes.severityand--fail-ondecide whether a failed result blocks.
Populated clauses within if are combined with AND semantics. Assertions are
also combined with AND semantics.
Rules can emit flags instead of asserting:
- id: design-review-signal
family: web-component
severity: info
if:
changedAny: [source]
kinExists: [figma]
actions:
emit: [designReviewRequired]
message: "A component with a Figma sidecar changed."
Flags are sorted and deduplicated in machine output, which makes them safe input for later CI steps.
Severity versus process failure¶
info, warn, and error describe rule results. The command's threshold
is separate:
| Result | Default --fail-on error |
--fail-on warn |
|---|---|---|
| Failed info rule | Does not block | Does not block |
| Failed warning rule | Does not block | Blocks |
| Failed error rule | Blocks | Blocks |
This means a report can contain Status: fail for a warning while the command
still exits 0. Use --fail-on warn when warnings should be policy gates.
Determinism¶
Kyn sorts changed files, family instances, rule results, expected paths, and flags. Given the same repository state, config, and change set, local and CI runs produce the same ordering and exit behavior.