{"id":16875660,"url":"https://github.com/kilo59/ruff-sync","last_synced_at":"2026-04-09T05:03:49.878Z","repository":{"id":222059119,"uuid":"639977747","full_name":"Kilo59/ruff-sync","owner":"Kilo59","description":"Keep ruff configuration files in sync","archived":false,"fork":false,"pushed_at":"2026-03-29T15:51:21.000Z","size":2785,"stargazers_count":1,"open_issues_count":9,"forks_count":5,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-29T16:46:25.419Z","etag":null,"topics":["code-standards","linting","pre-commit","python","ruff","toml","tomlkit"],"latest_commit_sha":null,"homepage":"https://kilo59.github.io/ruff-sync/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Kilo59.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2023-05-12T17:08:51.000Z","updated_at":"2026-03-29T15:37:10.000Z","dependencies_parsed_at":"2024-02-12T04:33:04.281Z","dependency_job_id":"19b18c8e-d101-495a-b31e-f645d23d8a42","html_url":"https://github.com/Kilo59/ruff-sync","commit_stats":null,"previous_names":["kilo59/ruff-sync"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/Kilo59/ruff-sync","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kilo59%2Fruff-sync","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kilo59%2Fruff-sync/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kilo59%2Fruff-sync/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kilo59%2Fruff-sync/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Kilo59","download_url":"https://codeload.github.com/Kilo59/ruff-sync/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kilo59%2Fruff-sync/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31374051,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T17:53:18.093Z","status":"ssl_error","status_checked_at":"2026-04-03T17:53:17.617Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-standards","linting","pre-commit","python","ruff","toml","tomlkit"],"created_at":"2024-10-13T15:36:43.757Z","updated_at":"2026-04-09T05:03:49.872Z","avatar_url":"https://github.com/Kilo59.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/Kilo59/ruff-sync/main/docs/assets/ruff_sync_banner.png\" alt=\"ruff-sync banner\" style=\"max-width: 600px; width: 100%; height: auto; margin-bottom: 1rem;\"\u003e\n  \u003cbr\u003e\n  \u003ca href=\"https://kilo59.github.io/ruff-sync/\"\u003e\u003cimg src=\"https://img.shields.io/badge/docs-MkDocs-blue.svg\" alt=\"Documentation\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://pypi.org/project/ruff-sync/\"\u003e\u003cimg src=\"https://img.shields.io/pypi/v/ruff-sync\" alt=\"PyPI version\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/Kilo59/ruff-sync\"\u003e\u003cimg src=\"https://codecov.io/gh/Kilo59/ruff-sync/graph/badge.svg?token=kMZw0XtoFW\" alt=\"codecov\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://results.pre-commit.ci/latest/github/Kilo59/ruff-sync/main\"\u003e\u003cimg src=\"https://results.pre-commit.ci/badge/github/Kilo59/ruff-sync/main.svg\" alt=\"pre-commit.ci status\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/astral-sh/ruff\"\u003e\u003cimg src=\"https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json\" alt=\"Ruff\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://wily.readthedocs.io/\"\u003e\u003cimg src=\"https://img.shields.io/badge/%F0%9F%A6%8A%20wily-passing-brightgreen.svg\" alt=\"Wily\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n# ruff-sync\n\n**Keep your Ruff config consistent across multiple projects.**\n\n`ruff-sync` is a CLI tool that pulls a canonical [Ruff](https://docs.astral.sh/ruff/) configuration from an upstream `pyproject.toml` or `ruff.toml` (hosted anywhere — GitHub, GitLab, or any raw URL) and merges it into your local project, preserving your comments, formatting, and project-specific overrides.\n\n---\n\n## Table of Contents\n\n- [Documentation](https://kilo59.github.io/ruff-sync/)\n- [The Problem](#the-problem)\n- [How It Works](#how-it-works)\n- [Quick Start](#quick-start)\n- [Key Features](#key-features)\n- [Ruff Inspect (TUI)](#ruff-inspect-tui)\n- [Configuration](#configuration)\n- [Pre-commit Integration](#pre-commit-integration)\n- [CI Integration](#ci-integration)\n- [Agent Skill](#agent-skill)\n- [Troubleshooting](https://kilo59.github.io/ruff-sync/stable/troubleshooting/)\n- [API Reference](https://kilo59.github.io/ruff-sync/stable/reference/ruff_sync/)\n- [Example Workflow](#example-workflow)\n- [Detailed Check Logic](#detailed-check-logic)\n- [Dogfooding](#dogfooding)\n- [License](#license)\n\n## The Problem\n\nIf you maintain more than one Python project, you've probably copy-pasted your `[tool.ruff]` config between repos more than once. When you decide to enable a new rule or bump your target Python version, you get to do it again — in _every_ repo. Configs drift, standards diverge, and your \"shared\" style guide becomes a polite suggestion.\n\n### How Other Ecosystems Solve This\n\n| Ecosystem | Mechanism | Limitation for Ruff users |\n|-----------|-----------|---------------------------|\n| **ESLint** | [Shareable configs](https://eslint.org/docs/latest/extend/shareable-configs) — publish an npm package, then `extends: [\"my-org-config\"]` | Requires a package registry (npm). Python doesn't have an equivalent convention. |\n| **Prettier** | [Shared configs](https://prettier.io/docs/sharing-configurations) — same npm-package pattern, referenced via `\"prettier\": \"@my-org/prettier-config\"` in `package.json` | Same — tightly coupled to npm. |\n| **Ruff** | [`extend`](https://docs.astral.sh/ruff/configuration/#config-file-discovery) — extend from a _local_ file path (great for monorepos) | Only supports local paths. No native remote URL support ([requested in astral-sh/ruff#12352](https://github.com/astral-sh/ruff/issues/12352)). |\n\nRuff's `extend` is perfect inside a monorepo, but if your projects live in **separate repositories**, there's no built-in way to inherit config from a central source.\n\n**That's what `ruff-sync` does.**\n\n### How It Works\n\n```\n┌─────────────────────────────┐\n│  Upstream repo              │\n│  (your \"source of truth\")   │\n│                             │\n│  pyproject.toml             │\n│    [tool.ruff]              │\n│    target-version = \"py310\" │\n│    lint.select = [...]      │\n└──────────┬──────────────────┘\n           │  ruff-sync downloads\n           │  \u0026 extracts [tool.ruff]\n           ▼\n┌─────────────────────────────┐\n│  Your local project         │\n│                             │\n│  pyproject.toml             │\n│    [tool.ruff]  ◄── merged  │\n│    # your comments kept ✓   │\n│    # formatting kept ✓      │\n│    # per-file-ignores kept ✓│\n└─────────────────────────────┘\n```\n\n1. You point `ruff-sync` at the URL of your canonical configuration (repository, directory, or direct file).\n2. It downloads the file and extracts the configuration (from `[tool.ruff]` in `pyproject.toml` or the top-level in `ruff.toml`).\n3. It **merges** the upstream config into your local project — updating values that changed, adding new rules, but preserving your local comments, whitespace, and any sections you've chosen to exclude (like `per-file-ignores`).\n\nNo package registry. No publishing step. Just a URL.\n\n## Quick Start\n\n### Install\n\nSee the [Installation Guide](https://kilo59.github.io/ruff-sync/stable/installation/) for more detailed instructions.\n\nWith [uv](https://docs.astral.sh/uv/) (recommended):\n\n```console\nuv tool install ruff-sync\n```\n\nWith [pipx](https://pipx.pypa.io/stable/):\n\n```console\npipx install ruff-sync\n```\n\nWith [pip](https://pip.pypa.io/en/stable/):\n\n```console\npip install ruff-sync\n```\n\n### Usage\n\n**The Basic Sync**\n\n```console\n# Pull rules from a central repository into your current project\nruff-sync https://github.com/my-org/standards\n```\n\n**Persistent Configuration**\n\n```console\n# If configured in pyproject.toml (see Configuration), simply run:\nruff-sync\n```\n\n**Initializing a New Project**\n\n```console\n# Scaffold a new pyproject.toml if your directory is empty\nruff-sync https://github.com/my-org/standards --init\n```\n\n**Syncing Subdirectories or Specific Files**\n\n```console\nruff-sync https://github.com/my-org/standards/tree/main/configs/shared\nruff-sync https://github.com/my-org/standards/blob/main/pyproject.toml\n```\n\n**Using Git (SSH/HTTP)**\n\n```console\n# Clones efficiently (depth 1, blob:none) to extract the config\nruff-sync git@github.com:my-org/standards.git\n```\n\n**Excluding Specific Rules**\n\n```console\n# Exclude specific sections from being overwritten using dotted paths\nruff-sync --exclude lint.ignore\n```\n\n**Checking for Drift (CI)**\n\n```console\n# Verify local config matches upstream. Exits 1 if config is out of sync.\n# If opted in via --pre-commit, exits 2 if only the pre-commit hook is out of sync.\nruff-sync check https://github.com/my-org/standards\n\n# Semantic check — ignores cosmetic differences like comments and whitespace\nruff-sync check --semantic\n```\n\nSee the [Usage documentation](https://kilo59.github.io/ruff-sync/stable/usage/) for more detailed examples and advanced workflows.\n\n## Key Features\n\n- 🏗️ **Format-preserving merges** — Uses [tomlkit](https://github.com/sdispater/tomlkit) under the hood, so your comments, whitespace, and TOML structure are preserved. No reformatting surprises.\n- 📂 **Upstream Layers** — Merge configurations from several sources sequentially (e.g., base company config + team-specific overrides).\n- 🌐 **GitHub \u0026 GitLab URL support** — Automatically converts GitHub/GitLab repository URLs, tree (directory) URLs, or blob (file) URLs to raw content URLs. (See [URL Resolution Guide](https://kilo59.github.io/ruff-sync/stable/url-resolution/))\n- 🔍 **Smart configuration discovery** — Point at a directory and `ruff-sync` will automatically find your config. It checks `pyproject.toml`, `ruff.toml`, and `.ruff.toml` (in that order).\n- 📥 **Git clone support** — If the URL starts with `git@` or uses the `ssh://`, `git://`, or `git+ssh://` schemes, `ruff-sync` will perform an efficient shallow clone (using `--filter=blob:none` and `--no-checkout`) to safely extract the configuration with minimal network traffic.\n- 🛡️ **Selective exclusions** — Keep project-specific overrides (like `per-file-ignores` or `target-version`) from being clobbered by the upstream config.\n- 🌍 **Works with any host** — GitHub, GitLab, Bitbucket, private SSH servers, or any raw URL that serves a `pyproject.toml` or `ruff.toml`.\n- 🤖 **CI-ready `check` command** — Verify that your local config is in sync without modifying anything. Exits 1 if out of sync, making it perfect for pre-merge gates. ([See detailed logic](#detailed-check-logic))\n- 🧠 **Semantic mode** — Use `--semantic` to ignore cosmetic differences (comments, whitespace) and only fail on real value changes.\n- 🔗 **Pre-commit hook sync** — Use `--pre-commit` to automatically keep your `ruff-pre-commit` hook version in `.pre-commit-config.yaml` matching your project's Ruff version.\n- 🦾 **Agent Skill** — Ships a bundled [Agent Skill](https://kilo59.github.io/ruff-sync/stable/agent-skill/) so AI coding agents can guide you through setup, configuration, and troubleshooting automatically.\n- 📊 **Multiple Output Formats** — Supports `text`, `json`, and GitHub Actions `github` (inline annotations) formats for seamless integration with both human developers and CI/CD pipelines.\n\n## Ruff Inspect (TUI)\n\n`ruff-inspect` is an **experimental** interactive Terminal User Interface for exploring your Ruff configuration and rule documentation — shipped as an optional extra.\n\n```console\n# Install with TUI support\nuv tool install \"ruff-sync[tui]\"\n\n# Launch the inspector\nruff-inspect\n```\n\n![Ruff Inspect TUI — rule detail view for F401 unused-import showing status, fix availability, description and rationale](docs/assets/screenshots/rule_details.svg)\n\n\u003e [!NOTE]\n\u003e This feature is experimental and subject to change. See the [Ruff Config Inspection](https://kilo59.github.io/ruff-sync/stable/inspect/) page for full details.\n\n## Configuration\n\nPoint `ruff-sync` at your upstream source and it will handle the rest. See the [Full Configuration Guide](https://kilo59.github.io/ruff-sync/stable/configuration/) for all available options.\n\nYou can configure `ruff-sync` itself in your `pyproject.toml`:\n\n```toml\n[tool.ruff-sync]\n# The source of truth for your Ruff configuration\nupstream = \"https://github.com/my-org/standards\"\n\n# Automatically sync the pre-commit Ruff hook version\npre-commit-version-sync = true\n\n# Use simple names for top-level keys, and dotted paths for nested keys\nexclude = [\n    \"target-version\",                      # Top-level [tool.ruff] key — projects target different Python versions\n    \"lint.per-file-ignores\",                # Project-specific file overrides\n    \"lint.ignore\",                         # Project-specific rule suppressions\n    \"lint.isort.known-first-party\",         # Every project has different first-party packages\n    \"lint.flake8-tidy-imports.banned-api\",  # Entire plugin section — project-specific banned APIs\n    \"lint.pydocstyle.convention\",          # Teams may disagree on google vs numpy vs pep257\n]\n```\n\nThis sets the default upstream and exclusions so you don't need to pass them on the command line every time.\n_Note: Any explicitly provided CLI arguments will override the values in `pyproject.toml`._\n\n### Advanced Configuration\n\nHere are all the possible values that can be provided in `[tool.ruff-sync]` along with their explanations and defaults:\n\n```toml\n[tool.ruff-sync]\n# The source of truth URL(s) for your Ruff configuration. (Required, unless passed via CLI)\n# Accepts a single string URL or a list of URLs.\nupstream = [\"https://github.com/my-org/standards\", \"https://github.com/my-org/team-tweaks\"]\n\n# A list of config keys to exclude from being synced. (Default: [\"lint.per-file-ignores\"])\n# Use simple names for top-level keys, and dotted paths for nested keys.\nexclude = [\n    \"target-version\",\n    \"lint.per-file-ignores\",\n]\n\n# The branch, tag, or commit hash to use when resolving a Git repository URL. (Default: \"main\")\nbranch = \"develop\"\n\n# The directory path within the repository where the config is located. (Default: \"\")\n# Useful if the upstream config is not at the repository root.\npath = \"config/ruff\"\n\n# The local target directory or file to sync into. (Default: \".\")\nto = \".\"\n\n# Keep the pre-commit Ruff hook version in sync with the project's Ruff version. (Default: false)\npre-commit-version-sync = true\n```\n\n## Pre-commit Integration\n\nEnsure your configuration is always in sync before every commit. Add this to your `.pre-commit-config.yaml`:\n\n```yaml\n- repo: https://github.com/Kilo59/ruff-sync\n  rev: v0.1.3  # Use the latest version\n  hooks:\n    - id: ruff-sync-check\n```\n\nSee the [Pre-commit Guide](https://kilo59.github.io/ruff-sync/stable/pre-commit/) for more details.\n\n## CI Integration\n\nThe `check` command is designed for use in CI pipelines. Add it as a step to catch config drift before it merges. See the [CI Integration Guide](https://kilo59.github.io/ruff-sync/stable/ci-integration/) for more details.\n\n```yaml\n# .github/workflows/ci.yaml\n- name: Check ruff config is in sync\n  run: |\n    ruff-sync check --semantic --output-format github\n```\n\nWith `--semantic`, minor reformatting of your local file won't cause a false positive — only actual rule or value differences will fail the check.\n\nTo see exactly what's drifted, omit `--no-diff` (the default) and the output will include a unified diff:\n\n```console\n$ ruff-sync check --semantic\n🔍 Checking Ruff sync status...\n❌ Ruff configuration at pyproject.toml is out of sync!\n--- local (semantic)\n+++ upstream (semantic)\n@@ -5,6 +5,7 @@\n   \"select\": [\n+    \"PERF\",\n     \"RUF\",\n     ...\n   ]\n```\n\n\u003e [!TIP]\n\u003e See the [Best Practices](https://kilo59.github.io/ruff-sync/stable/best-practices/) guide for recommendations on whether to make your CI checks blocking or informational.\n\n\n## Agent Skill\n\n`ruff-sync` ships a bundled [Agent Skill](https://agentskills.io/home) at [`.agents/skills/ruff-sync-usage/`](.agents/skills/ruff-sync-usage/). AI coding agents that support the [Agent Skills format](https://agentskills.io/what-are-skills) (GitHub Copilot, Claude Code, Cursor, etc.) will automatically use it to guide you through setup, configuration, CI integration, and troubleshooting — without you needing to explain the tool each time.\n\nSee the **[Agent Skill guide](https://kilo59.github.io/ruff-sync/stable/agent-skill/)** for details.\n\n## Example Workflow\n\nA typical setup for an organization:\n\n1. **Create a \"standards\" repo** with your canonical `pyproject.toml` containing your shared `[tool.ruff]` config.\n2. **In each project**, run `ruff-sync` pointing at that repo — either manually, in a Makefile, or as a CI step.\n3. **When you update the standard**, re-run `ruff-sync` in each project to pull the changes. Your local comments and `per-file-ignores` stay intact.\n\n```console\n# In each project repo:\nruff-sync https://github.com/my-org/python-standards\ngit diff pyproject.toml  # review the changes\ngit commit -am \"sync ruff config from upstream\"\n```\n\n### Curated Examples\n\nWhile `ruff-sync` is designed to sync from _any_ repository or URL of your choosing, this repository also provides a few curated configurations in the [`configs/`](./configs/) directory that you can use directly. See the [Pre-defined Configs Guide](https://kilo59.github.io/ruff-sync/stable/pre-defined-configs/) for more detailed examples and advanced usage.\n\n#### Kitchen Sink\n\nAn exhaustive configuration that explicitly enables and documents almost all available Ruff rules. Great for establishing a strict baseline.\n\n```console\n# Directory URL (recommended)\nruff-sync https://github.com/Kilo59/ruff-sync/tree/main/configs/kitchen-sink\n\n# Direct file URL (blob)\nruff-sync https://github.com/Kilo59/ruff-sync/blob/main/configs/kitchen-sink/ruff.toml\n\n# Raw content URL\nruff-sync https://raw.githubusercontent.com/Kilo59/ruff-sync/main/configs/kitchen-sink/ruff.toml\n\n# Git SSH URL (clones the repo)\nruff-sync git@github.com:Kilo59/ruff-sync.git --path configs/kitchen-sink\n```\n\n#### FastAPI \u0026 Async\n\nTailored for modern web applications. Includes rules for `asyncio`, security (`flake8-bandit`), and Pydantic-friendly naming conventions.\n\n```console\n# Using the --path option with the repository root\nruff-sync https://github.com/Kilo59/ruff-sync --path configs/fastapi\n\n# Directory URL\nruff-sync https://github.com/Kilo59/ruff-sync/tree/main/configs/fastapi\n```\n\n#### Default Syncing\n\nSet your preferred standard as the default in your `pyproject.toml`:\n\n```toml\n[tool.ruff-sync]\nupstream = \"https://github.com/Kilo59/ruff-sync\"\npath = \"configs/fastapi\"\n```\n\n## Bootstrapping a New Project\n\nBy default, `ruff-sync` requires an existing configuration file (`pyproject.toml` or `ruff.toml`) to merge into. If you are starting a fresh project and want to initialize it with your organization's Ruff settings, you can use the `--init` flag to scaffold a new file automatically.\n\n```bash\n# Create a new pyproject.toml (or ruff.toml) pre-configured with upstream settings\nruff-sync https://github.com/my-org/standards --init\n```\n\n`ruff-sync` will automatically serialize the upstream URL (and any other CLI arguments like exclusions) into a new `[tool.ruff-sync]` section in your `pyproject.toml` so that future syncs can be performed simply by running `ruff-sync`. To prevent accidental credential leaks, `ruff-sync` will refuse to serialize this section if it detects a username or password in the upstream URL.\n\nIf you wish to update an existing configuration with a new upstream URL and save it permanently, use the `--save` flag:\n\n```bash\nruff-sync https://github.com/my-org/new-standards --save\n```\n\n`ruff-sync` seamlessly supports both `pyproject.toml` and standalone `ruff.toml` (or `.ruff.toml`) files. If your local target is a directory, it will look for configuration files in the following order: `ruff.toml` -\u003e `.ruff.toml` -\u003e `pyproject.toml`. If your upstream source or your local target is a `ruff.toml`, it will automatically adapt and sync the root configuration rather than looking for a `[tool.ruff]` section.\n\n## Detailed Check Logic\n\nWhen you run `ruff-sync check`, it follows this process to determine if your project has drifted from the upstream source:\n\n```mermaid\nflowchart TD\n    Start([Start]) --\u003e Local[Read Local Configuration]\n    Local --\u003e Upstreams{For each Upstream}\n    Upstreams --\u003e Download[Download/Clone Configuration]\n    Download --\u003e Extract[Extract section if needed]\n    Extract --\u003e Exclude[Apply Exclusions]\n    Exclude --\u003e Merge[Merge into in-memory Doc]\n    Merge --\u003e Upstreams\n    Upstreams -- Done --\u003e Comparison\n\n    subgraph Comparison [Comparison Logic]\n        direction TB\n        SemanticNode{--semantic?}\n        SemanticNode -- Yes --\u003e Unwrap[Unwrap TOML objects to Python Dicts]\n        Unwrap --\u003e CompareVal[Compare Key/Value Pairs]\n        SemanticNode -- No --\u003e CompareFull[Compare Full File Strings]\n    end\n\n    Merge --\u003e Comparison\n\n    CompareVal --\u003e ResultNode{Ruff Sync Match?}\n    CompareFull --\u003e ResultNode\n\n    ResultNode -- Yes --\u003e Success([Exit 0: In Sync])\n\n    ResultNode -- No --\u003e Diff[Generate Diff]\n    Diff --\u003e Fail([Exit 1: Ruff Config Out of Sync])\n\n    %% Styling\n    style Start fill:#2563eb,color:#fff,stroke:#1d4ed8\n    style Success fill:#16a34a,color:#fff,stroke:#15803d\n    style Fail fill:#dc2626,color:#fff,stroke:#b91c1c\n    style ResultNode fill:#ca8a04,color:#fff,stroke:#a16207\n    style Comparison fill:none,stroke:#9e9e9e,stroke-dasharray: 5 5,stroke-width:2px\n    style SemanticNode fill:#4b5563,color:#fff,stroke:#374151\n```\n\n## Dogfooding\n\nTo see `ruff-sync` in action, this project automatically \"dogfoods\" its own configuration. Every pull request runs a `ruff-sync check` against the repository's own `pyproject.toml` using the `--output-format github` flag, providing real-time feedback and inline annotations whenever configuration drift is detected.\n\nYou can also run these checks manually or experiment with syncing:\n\n[**Check if this project is in sync with its upstream:**](./scripts/check_dogfood.sh)\n\n```console\n./scripts/check_dogfood.sh\n```\n\n[**Or sync from a large upstream like Pydantic's config:**](./scripts/pull_dogfood.sh)\n\n```console\n# Using a HTTP URL\n./scripts/pull_dogfood.sh\n# Using a Git URL\n./scripts/gitclone_dogfood.sh\n```\n\nThis will download Pydantic's Ruff configuration and merge it into the local `pyproject.toml`. You can then use `git diff` to see how it merged the keys while preserving the existing structure and comments.\n\n**To revert the changes after testing:**\n\n```console\ngit checkout pyproject.toml\n```\n\n## License\n\n[MIT](LICENSE.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkilo59%2Fruff-sync","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkilo59%2Fruff-sync","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkilo59%2Fruff-sync/lists"}