{
  "markdown": "# ViewDoctor\n\n<img src=\"docs/assets/viewdoctor-icon-1024.png\" alt=\"ViewDoctor\" width=\"120\">\n\n**Check SwiftUI diffs with module ownership attached.**\n\nViewDoctor maps modules from Swift Package Manager, Tuist, Xcode projects, and\ncommon source layouts before it scans SwiftUI code. Run it after a human or\ncoding agent changes a diff; the result stays local and can be read as terminal\ntext, compact agent JSON, full versioned JSON, or SARIF.\n\n```text\nModules/Profile/Sources/ProfileView.swift:42:18: warning: VD001 [tuist:Modules/Profile/Profile]: DateFormatter is constructed inside a body property.\nViewDoctor: 1 finding(s) in 12 file(s), 4 module(s).\n```\n\n## The review loop\n\nA small generated diff should not require sending the repository back to a\ngeneral model just to look for three known SwiftUI risks. ViewDoctor gives those\nchecks stable rule IDs, exact locations, module ownership, and bounded output:\n\n`edit -> scan changed files -> fix findings -> verify once`\n\n- It reads source locally and has no telemetry.\n- Manifest-derived identifiers keep findings useful in large repositories.\n- Agent JSON keeps the location, module, message, and fix without repeating\n  verbose human context; full JSON keeps explanations for integrations.\n- Deterministic ordering and exit codes make the same command useful in CI.\n\nViewDoctor complements the Swift compiler, SwiftLint, Periphery, and\nInstruments. It does not replace builds, profiling, or architecture review.\n\n## Install and run\n\nRequires Swift 6.2 or newer for source builds.\n\n```sh\ngit clone https://github.com/KamnevVladimir/ViewDoctor.git\ncd ViewDoctor\nswift build -c release\n.build/release/viewdoctor scan /path/to/project\n```\n\nAnalyze only the current git diff—the recommended mode for coding agents:\n\n```sh\nviewdoctor scan . --git-diff --format agent\nviewdoctor scan . --base origin/main --format agent\n```\n\n`--git-diff` includes tracked changes and new untracked Swift files. A newly\ngenerated view is therefore not skipped just because it has not been added to\nGit yet.\n\nRun a strict pre-commit checkpoint against the index only:\n\n```sh\nviewdoctor scan . --staged --fail-on warning\n```\n\nInspect discovered modules and dependencies:\n\n```sh\nviewdoctor graph .\n```\n\nGenerate GitHub Code Scanning output:\n\n```sh\nviewdoctor scan . --base origin/main --format sarif > viewdoctor.sarif\n```\n\nDiscover commands and the installed version without opening the README:\n\n```sh\nviewdoctor --help\nviewdoctor --version\n```\n\n## Changed files, pre-commit, and CI\n\nThese are separate checkpoints rather than aliases:\n\n| Workflow | Command | What is included |\n|---|---|---|\n| Agent or human checkpoint | `--git-diff` | tracked working-tree/index changes plus untracked Swift files |\n| Pull request checkpoint | `--base origin/main` | changes since the base plus untracked Swift files |\n| Pre-commit hook | `--staged` | staged Swift files only |\n| Full audit | no Git option | every discovered Swift file |\n\nUse `--fail-on warning` when warnings must block a hook or CI job. The default\nremains `error`, so adopting ViewDoctor does not silently turn every warning\ninto a breaking gate.\n\n## Multi-module architecture\n\nViewDoctor builds a normalized graph from all manifests it discovers:\n\n| Build system | Discovery source | Module ownership |\n|---|---|---|\n| SwiftPM | `Package.swift` targets and dependencies | `Sources/<Target>` |\n| Tuist | `Project.swift` targets, source globs, and project paths | project/target source roots |\n| Xcode | `.xcodeproj/project.pbxproj` native targets | target source roots |\n| Folder layout | `Modules`, `Apps`, `Sources`, `Tests` | deterministic fallback |\n\nWhen providers overlap, the longest matching source root wins. The graph model\nexposes a reverse dependency-cone operation for integrations and future\naffected-module rules. The current three source rules still scan only the\nselected files; they do not pretend to validate unchanged dependents.\n\nManifest calls are parsed as bounded SwiftSyntax expressions, so one target's\ndependencies cannot bleed into the next target. Tuist `.project(target:path:)`\nedges are resolved relative to the manifest or project root, and self-edges are\ndiscarded. `viewdoctor graph .` also emits diagnostics when a Tuist manifest\nimports `ProjectDescriptionHelpers`: helper-generated targets are executable\nSwift and cannot be expanded by a static parser. ViewDoctor reports that limit\ninstead of presenting a partial graph as complete.\n\n## Rules\n\n| Rule | Default | Detects |\n|---|---|---|\n| `VD001` | warning | reusable or expensive object construction in SwiftUI `body` |\n| `VD002` | note | collection transformations repeated inside `body` |\n| `VD003` | warning | detached task creation inside `body` |\n\nRules intentionally use conservative language: a finding is a reviewable risk,\nnot a claim that profiling has proven a performance regression.\n\nThe current release has three rules. It does not yet enforce dependency\ndirection, detect cycles, or prove runtime performance. Those are explicit\nroadmap items rather than implied capabilities.\n\n## GitHub Action\n\nRun ViewDoctor in CI on a macOS runner with Swift 6.2 or newer. The action\nbuilds the pinned Swift package, scans the checked-out repository, and can\nupload SARIF findings to GitHub Code Scanning.\n\n```yaml\nname: ViewDoctor\n\non:\n  pull_request:\n\npermissions:\n  contents: read\n  security-events: write\n\njobs:\n  analyze:\n    runs-on: macos-26\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n      - uses: KamnevVladimir/ViewDoctor@v0\n        with:\n          diff-base: origin/main\n          fail-on: warning\n```\n\nSet `upload-sarif: false` when the workflow cannot grant\n`security-events: write`, such as a restricted fork workflow. Use a full\nrelease tag such as `v0.1.7` when you need an immutable dependency; `v0` is\nthe maintained major-version pointer.\n\n## Output contract\n\nFull JSON reports include `schemaVersion`, relative source locations, stable\nrule IDs, module IDs, explanations, remediation, and a module graph summary.\n`--format agent` is a smaller JSON contract for the edit/fix loop: it retains\nthe exact finding and fix but replaces the repeated module list with a count.\nIntegrations that need every field should consume full JSON or SARIF.\n\nOptional `.viewdoctor.json`:\n\n```json\n{\n  \"excludedPaths\": [\"Generated\", \"Vendor\"],\n  \"disabledRules\": [\"VD002\"],\n  \"minimumSeverity\": \"warning\",\n  \"maxFindings\": 100\n}\n```\n\n`minimumSeverity` controls which findings are reported. `--fail-on` controls\nonly the process exit code, so a CI gate can be stricter without changing the\nshared report configuration.\n\nExit codes:\n\n- `0`: scan completed below the `--fail-on` threshold;\n- `1`: at least one finding met the threshold;\n- `2`: arguments or scan startup failed.\n\n## Coding-agent integration\n\nThe repository contains a Codex/OpenAI skill and local MCP server in `plugin/`.\nThe MCP tools call the same CLI without a shell, keep source on the local\nmachine, and expose scans and module graphs to coding agents. The CLI remains\nthe source of truth; the skill and MCP server are thin adapters.\n\nThe release also includes a macOS MCP Bundle. Install\n[`ViewDoctor-v0.1.7.mcpb`](https://github.com/KamnevVladimir/ViewDoctor/releases/download/v0.1.7/ViewDoctor-v0.1.7.mcpb)\nin any client that supports MCPB, or discover it in the official MCP Registry as\n`io.github.KamnevVladimir/viewdoctor`. The bundle contains the local CLI and\nstdio adapter; repository source is not sent to a hosted service.\n\nThe workflow changes in this release came from concrete integration failures,\nnot a larger rule wishlist. The evidence and scope decisions are documented in\n[`docs/PAIN_DRIVEN_UX.md`](docs/PAIN_DRIVEN_UX.md).\n\n## Roadmap\n\n- baselines for existing findings;\n- module dependency-cycle and undeclared-import rules;\n- body complexity and identity rules with low-noise fixtures;\n- signed release artifacts and package-manager installation;\n- incremental cache and dependency-cone analysis.\n\n## Privacy\n\nViewDoctor reads local Swift and manifest files. It does not make network\nrequests during analysis and does not collect telemetry. Public examples and\ntests use synthetic source only.\n\nBuilt by [KamnevApps](https://kamnevapps.com) while shipping production SwiftUI\napplications. Licensed under MIT.\n",
  "bytes": 8320,
  "sha": "2fd62b0760d421c69d6fdd7a908966270653cc61add903a02ccd364ae41a4a96",
  "repo_slug": "kamnevvladimir/viewdoctor",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_kamnevvladimir_viewdoctor_1f968f23/readme"
}