Skip to content

Repository files navigation

Rýni

A harness linter, written in Rust.

Install · Documentation · Built-in rules · Releases

Harness engineering is hard. Keeping a team aligned on it is harder. Your coding agents depend on instructions, skills, and Markdown docs that stay consistent as projects change. Ryni catches broken local links and invalid Agent Skills metadata before they get in the way.

  • Check your harness. Built-in checks for Markdown links and Agent Skills.
  • Run anywhere. Written in Rust, distributed as a standalone binary.
  • Start immediately. Run ryni check .. No configuration required.

Share team conventions: versioned local TOML packs select rules and configure preview checks for metadata, document sections, required files and duplicate skill names. See configuration and packs.

Install

macOS and Linux:

curl -LsSf https://github.com/computerlovetech/ryni/releases/latest/download/ryni-installer.sh | sh

Windows PowerShell:

powershell -ExecutionPolicy Bypass -c "irm https://github.com/computerlovetech/ryni/releases/latest/download/ryni-installer.ps1 | iex"

No Rust installation is needed. Follow the installer's PATH instructions, then run ryni --version. Rerun the installer to update. Prebuilt archives are also available on GitHub Releases.

For development, install from this repository with Rust and Cargo:

cargo install --path . --locked

See RELEASE.md for version pinning, custom install locations, and the release process.

Check

ryni check .              # Current directory
ryni check ./my-project   # A project directory
ryni check ./skills/review # A single skill directory

No configuration is needed. Ryni recursively checks .md and .markdown files (case-insensitive extensions) for broken local links. Files named exactly SKILL.md also receive all five Agent Skills metadata checks. Hidden directories such as .agents/skills are included unless ignored. Nested symlinks are skipped.

Ryni respects .gitignore, .ignore, .git/info/exclude, and global Git excludes, including applicable parent and nested ignore files. Git ignore rules apply inside Git repositories; .ignore also works outside them. Matching files are skipped even if tracked by Git. Global excludes can make scan coverage differ between your machine and CI.

ryni check . --no-ignore                  # Disable ignore-file filtering
ryni check . --exclude 'vendor/**' --exclude 'third_party/**'

--exclude accepts repeatable gitignore-style globs relative to the scan root and still applies with --no-ignore. Patterns containing a slash are relative to that root; patterns such as *.md match at any depth. Quote globs to prevent shell expansion. Filtering only controls which files are scanned: links to existing targets inside excluded directories remain valid.

Example output:

markdown-local-link: Target "docs/testing.md" does not exist
 --> README.md:3:1
  |
3 | [Testing](docs/testing.md)
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^

Found 1 error.

Diagnostics show the rule, file location, and source context. Broken links are underlined; skill metadata findings show a preview of the file without guessing an individual field location. Terminal output uses color; redirected output is plain text. Set NO_COLOR to disable color.

A clean scan prints All checks passed!. When no supported files are found, ryni prints No supported files found. and exits successfully.

Exit codes: 0 passed or no supported files, 1 violations, 2 execution error. Use the same command in CI. Files change only when --fix is explicitly enabled.

Built-in rules

Rule Status Check
skill-frontmatter stable SKILL.md must start with delimited YAML containing a mapping with unique string keys.
skill-name stable The name must contain 1–64 lowercase Unicode letters, numbers or hyphens, without leading, trailing or consecutive hyphens.
skill-directory-name stable The skill name must exactly match its containing directory.
skill-description stable The description must be a nonblank string of at most 1,024 Unicode characters.
skill-optional-fields stable Validate license, allowed-tools, compatibility and metadata against the Agent Skills field requirements.
markdown-local-link stable Relative Markdown links and images must point to existing files or directories. URL schemes and document anchors are skipped.

Malformed frontmatter produces one skill-frontmatter finding. Dependent checks are skipped for that file. Character limits count Unicode characters, not UTF-8 bytes. Names are not trimmed or Unicode-normalized.

These checks cover the requirements above, not full semantic compliance. They do not judge description quality, validate instruction bodies, require optional directories, or reject additional frontmatter fields.

Local Markdown links

Links resolve relative to the Markdown file containing them, including ../ paths. Images and reference-style links are checked too. Diagnostics point to the link's start (or its reference use), with one-based line and character column:

markdown-local-link: Target "docs/testing.md" does not exist
 --> README.md:12:1

[Guide](guide.md#installation) checks that guide.md exists; it does not check whether the heading exists. Queries are also removed before checking. URL-encoded paths such as my%20guide.md are decoded. Existing directories and links to files outside the scanned directory are accepted. Linked symlinks are resolved.

The rule skips URL schemes (including web and email links), root-relative links such as /docs/guide, network URLs, and same-document anchors. Code examples, frontmatter, raw HTML attributes, and plain-text paths are not checked. Undefined Markdown reference labels are not filesystem targets and are not checked.

Paths are checked literally: no automatic .md extension, website routing, or build-template expansion. Generated targets must already exist when checking; intentional broken links are reported too. Invalid filenames and paths that are too long produce findings without stopping the scan. Other inspection failures, such as permission errors, remain execution errors. There are no suppressions yet.

Configuration and automation

ryni check README.md --select markdown-local-link
ryni check . --output-format json
ryni check . --exclude vendor --respect-ignore
ryni settings .
ryni rule skill-directory-name
ryni check . --fix --unsafe-fixes

The six stable rules remain the default. Optional ryni.toml configuration and versioned local packs can select rules and add preview conventions. JSON results include structured findings, source positions, proposed fixes and execution errors. Incomplete scans retain available findings and exit with code 2.

The directory/name fix is unsafe: it changes skill identity and rewrites YAML formatting and comments. It requires explicit opt-in. See configuration, output and fixes, and the architecture guide.

Development

cargo run -- check .
cargo test --locked
cargo clippy --all-targets --locked -- -D warnings
cargo fmt --check

Checking this repository discovers the valid skill fixture in tests/fixtures/skills. Rule implementations live under src/rules/.

The opt-in repository benchmark scans 15 pinned open-source projects across 15 languages, records timings and diagnostics, and compares behavior against a reviewed baseline.

Documentation development

The MkDocs source lives in website/, with MkDocs Material and the shared Computerlove styling used by Umbod. Use uv to preview or build it:

uv run --locked --only-group docs mkdocs serve
uv run --locked --only-group docs mkdocs build --strict

Python is used for development tooling; the CLI is written in Rust. Documentation pull requests are built in CI. Changes merged to main deploy to GitHub Pages.

About

A harness linter, written in Rust.

Resources

Stars

7 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages