Skip to main content

Rýni

An opinionated linter for agent harnesses, written in Python.

Getting started · Usage · Rules · Plugins · Contributing

Agent instructions and skills are part of your codebase. Rýni helps you keep them consistent as your project grows, enforcing conventions for how harnesses are structured, shared, and maintained, with actionable diagnostics when they drift.

  • Validate skills. Check SKILL.md frontmatter for required metadata.
  • Keep instructions in sync. Check that CLAUDE.md links to its sibling AGENTS.md.
  • Check skill organization. Find misplaced skill sources, tracked installations, and missing or inconsistent local installations.
  • Choose your rules. Run the full catalog or select individual checks by ID.
  • Use it in automation. Get structured JSON output and predictable exit codes.
  • Add your own conventions. Distribute custom rules as Python packages.

Rýni's built-in checks run locally, without a model or API key, and do not modify files. The project is in early development; the CLI and plugin API may change.

Getting started

Rýni requires Python 3.14 or later. Git is required for the installed-skills ignore check (SKILL002).

Install from PyPI with uv:

uv tool install ryni

Or with pip:

pip install ryni

Then run Rýni in the project you want to check:

ryni check .

Usage

Check files, directories, or multiple paths:

ryni check .
ryni check skills/ AGENTS.md CLAUDE.md

List available rules:

ryni rule

Produce JSON for scripts and CI:

ryni check . --output-format json

The JSON report contains checked_files, findings, and errors. Each finding includes a path, line number, rule ID, and message. For repository-wide checks, checked_files also includes repository roots.

Exit code Meaning
0 Checks completed without findings.
1 Checks completed with findings.
2 Invalid invocation, execution error, or incomplete checks.

Reports preserve findings when another check fails. Runs with no applicable targets explicitly report zero checked targets.

Configuration and discovery

All registered rules, including installed plugins, run by default. Use --select to choose a comma-separated list of rule IDs. Configuration is currently through CLI options; Rýni does not read a configuration file.

File rules search the supplied paths recursively and select files by name. Discovery skips .git, .venv, venv, node_modules, __pycache__, .agents, .claude, .codex, and .github. You can check those locations by passing them explicitly. Directory symlinks are not traversed, and repeated paths are deduplicated without resolving symlinks. File discovery does not apply .gitignore patterns.

Repository rules inspect the nearest enclosing Git checkout for each supplied path, once per repository. Outside a Git checkout, they use the supplied directory or the file's parent directory. Selecting a single file does not narrow the scope of repository rules. Select only file rules when you want checks limited to those paths.

Rules

Rýni includes five deterministic rules:

ID Name Checks
SKILL001 skill-frontmatter SKILL.md starts with valid YAML frontmatter containing non-empty string name and description fields.
AGENT001 claude-agents-symlink Each existing CLAUDE.md is a symlink resolving to an existing sibling AGENTS.md.
SKILL002 installed-skills-gitignored Installed skill directories for configured agents are covered by repository .gitignore rules and are not tracked.
SKILL003 local-skills-source-location Locally owned skills live under a directory named skills/, with nested categories allowed.
SKILL004 local-skills-installed Local skills have a matching local-source skills-lock.json entry and matching installed SKILL.md files for agents configured in their source scope.

SKILL001 allows additional frontmatter fields and checks structure only. AGENT001 allows AGENTS.md without a corresponding CLAUDE.md. SKILL004 accepts copies and symlinks and checks installation evidence, not command history.

These rules express Rýni’s opinions about maintaining agent harnesses. They do not assess instruction quality or agent behavior. Semantic and hybrid rule kinds are reserved for future use; agent execution is not implemented.

Plugins

Extend Rýni with rules for your team's conventions. A Python package can export a ryni.models.Rule instance through the ryni.rules entry-point group.

In the plugin's pyproject.toml:

[project.entry-points."ryni.rules"]
example = "my_rules:EXAMPLE"

In my_rules.py:

from pathlib import Path

from ryni.models import Finding, Rule, RuleKind


def check_readme(path: Path) -> list[Finding]:
    if not path.read_text(encoding="utf-8").strip():
        return [Finding(str(path), 1, "CUSTOM001", "README must not be empty.")]
    return []


EXAMPLE = Rule(
    id="CUSTOM001",
    name="nonempty-readme",
    kind=RuleKind.DETERMINISTIC,
    description="README.md must contain text.",
    filename="README.md",
    evaluate=check_readme,
)

Install the plugin in the same Python environment as Rýni. Both check and rule load installed plugins; duplicate rule IDs are rejected. Plugins execute Python code, so only install packages you trust.

Evaluators receive a path and return a list of findings. They must not print or modify files. An evaluator exception produces an execution error and exit code 2, while other checks continue.

Contributing

Bug reports, rule proposals, documentation improvements, and pull requests are welcome. For a bug report, include the command you ran, a minimal example, and the expected and actual output. For a new rule, describe the convention it checks and show examples that should pass and fail.

Rýni currently lives in tools/ryni in this repository. From the repository root:

uv run ryni --help
uv run pytest tools/ryni/tests
uv run ruff check tools/ryni

The CLI handles commands and output, the engine discovers targets and runs checks, and the rule catalog registers built-in rules and loads plugins. Add built-in rules under src/ryni/rules/, register them in BUILTINS, and include tests under tests/.

Metadata

Release files for ryni 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ryni 0.1.0
File Size Uploaded Provenance
ryni-0.1.0.tar.gz 17.7 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for ryni 0.1.0
File Interpreter ABI Platform
ryni-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 33.3 kB

Release files / ryni-0.1.0.tar.gz

Download URL ryni-0.1.0.tar.gz
Size 17.7 kB
Tags Source
SHA-256 checksum
How to use checksums
01ffe331c85bba90eeb4696560837c5366698faa94200e294573f076ffdc65ed
BLAKE2b-256 checksum
How to use checksums
a6af691f1284cddcf42ddf69553283d274edd84c5802b2632d4f2856befd8042
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / ryni-0.1.0-py3-none-any.whl

Download URL ryni-0.1.0-py3-none-any.whl
Size 15.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d93e08cd567936ced986aa72a927a0310d75be259655088759e5799f25d73c37
BLAKE2b-256 checksum
How to use checksums
9064493f97319df3cacf8d8fd1d5e647b03411d70447bb511522dd1c609bfe83
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for ryni 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page