{"id":49960403,"url":"https://github.com/elixir-vibe/reach","last_synced_at":"2026-05-18T02:18:07.569Z","repository":{"id":351126119,"uuid":"1208797646","full_name":"elixir-vibe/reach","owner":"elixir-vibe","description":"Program dependence graph and architecture/code-flow analysis for BEAM projects","archived":false,"fork":false,"pushed_at":"2026-05-11T17:08:48.000Z","size":1784,"stargazers_count":130,"open_issues_count":0,"forks_count":9,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-05-11T17:31:07.522Z","etag":null,"topics":["data-flow","dependence-graph","elixir","erlang","program-analysis","slicing","static-analysis","taint-analysis"],"latest_commit_sha":null,"homepage":null,"language":"Elixir","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/elixir-vibe.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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":"2026-04-12T18:55:25.000Z","updated_at":"2026-05-11T17:10:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/elixir-vibe/reach","commit_stats":null,"previous_names":["dannote/reach","elixir-vibe/reach"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/elixir-vibe/reach","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-vibe%2Freach","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-vibe%2Freach/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-vibe%2Freach/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-vibe%2Freach/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elixir-vibe","download_url":"https://codeload.github.com/elixir-vibe/reach/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-vibe%2Freach/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33162480,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-17T22:39:12.733Z","status":"online","status_checked_at":"2026-05-18T02:00:06.436Z","response_time":71,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["data-flow","dependence-graph","elixir","erlang","program-analysis","slicing","static-analysis","taint-analysis"],"created_at":"2026-05-18T02:18:06.514Z","updated_at":"2026-05-18T02:18:07.560Z","avatar_url":"https://github.com/elixir-vibe.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Reach\n\nProgram dependence graph and release-safety toolkit for Elixir, Erlang, Gleam, JavaScript, and TypeScript.\n\nReach builds a graph of **what depends on what** in your code: control flow, call graph, data flow, effects, and OTP/process relationships. Use it to inspect risky functions, trace values, validate architecture policy, and generate interactive HTML reports.\n\nElixir 1.18+ / OTP 27+.\n\n## Installation\n\n```elixir\ndef deps do\n  [\n    {:reach, \"~\u003e 2.0\", only: [:dev, :test], runtime: false}\n  ]\nend\n```\n\nOptional dependencies enable richer output:\n\n```elixir\n{:jason, \"~\u003e 1.0\"},       # JSON output\n{:boxart, \"~\u003e 0.3.3\"},    # terminal graphs\n{:makeup, \"~\u003e 1.0\"},\n{:makeup_elixir, \"~\u003e 1.0\"},\n{:makeup_js, \"~\u003e 0.1\"}\n```\n\n## Quickstart\n\nGenerate an interactive report:\n\n```bash\nmix reach\n```\n\nMap the project:\n\n```bash\nmix reach.map\nmix reach.map --modules\nmix reach.map --coupling\nmix reach.map --hotspots\n```\n\nInspect a target:\n\n```bash\nmix reach.inspect MyApp.Accounts.create_user/1 --context\nmix reach.inspect lib/my_app/accounts.ex:42 --impact\nmix reach.inspect MyApp.Accounts.create_user/1 --why MyApp.Repo\n```\n\nTrace data:\n\n```bash\nmix reach.trace --from conn.params --to Repo\nmix reach.trace --variable changeset --in MyApp.Accounts.create_user/1\n```\n\nRun release checks:\n\n```bash\nmix reach.check --arch\nmix reach.check --changed --base main\nmix reach.check --smells --strict\nmix reach.check --arch --smells --write-baseline .reach-baseline.json\nmix reach.check --candidates\n```\n\nInspect OTP/process risks:\n\n```bash\nmix reach.otp\nmix reach.otp --concurrency\n```\n\n## Canonical CLI\n\nReach 2.x uses five canonical analysis tasks plus the HTML report task.\n\n| Command | Purpose |\n|---|---|\n| `mix reach` | Interactive HTML report |\n| `mix reach.map` | Project map: modules, coupling, hotspots, effects, depth, data flow |\n| `mix reach.inspect TARGET` | Target-local deps, impact, graph, context, data, candidates, why paths |\n| `mix reach.trace` | Data-flow, taint, and slicing workflows |\n| `mix reach.check` | CI/release checks: architecture, changed code, dead code, smells, candidates |\n| `mix reach.otp` | OTP/process analysis: behaviours, state machines, supervision, concurrency, coupling |\n\nUse `--format json` for automation. Canonical commands emit pure JSON envelopes with stable command names.\n\nOlder task names were removed in Reach 2.0 and fail fast with migration guidance. See the [Canonical CLI guide](guides/cli.md).\n\n## Configuration\n\nReach reads `.reach.exs` for architecture and change-safety policy:\n\n```elixir\n[\n  layers: [\n    web: \"MyAppWeb.*\",\n    domain: \"MyApp.*\",\n    data: [\"MyApp.Repo\", \"MyApp.Schemas.*\"]\n  ],\n  deps: [\n    forbidden: [\n      {:domain, :web},\n      {:data, :web}\n    ]\n  ],\n  source: [\n    forbidden_modules: [\"MyApp.Legacy.*\"],\n    forbidden_files: [\"lib/my_app/legacy/**\"]\n  ],\n  calls: [\n    forbidden: [\n      {\"MyApp.Domain.*\", [\"IO.puts\", \"Jason.encode!\"]}\n    ]\n  ],\n  tests: [\n    hints: [\n      {\"lib/my_app/accounts/**\", [\"test/my_app/accounts_test.exs\"]}\n    ]\n  ]\n]\n```\n\nStart from [`examples/reach.exs`](examples/reach.exs). See the [configuration guide](guides/configuration.md) for the full reference and narrative examples.\n\n## Library API\n\nReach can also analyze snippets, files, and source directories directly:\n\n```elixir\ngraph = Reach.string_to_graph!(\"\"\"\ndef run(input) do\n  command = String.trim(input)\n  System.cmd(\"sh\", [\"-c\", command])\nend\n\"\"\")\n\n[cmd_call] = Reach.nodes(graph, type: :call, module: System, function: :cmd)\nReach.backward_slice(graph, cmd_call.id)\n```\n\nCommon queries:\n\n```elixir\nReach.backward_slice(graph, node_id)\nReach.forward_slice(graph, node_id)\nReach.taint_analysis(graph, sources: [function: :params], sinks: [module: System, function: :cmd])\nReach.independent?(graph, node_a.id, node_b.id)\nReach.data_flows?(graph, source_id, sink_id)\n```\n\n## Documentation\n\nHexDocs guides are organized by workflow:\n\n- Overview, installation, and quickstart\n- Canonical CLI and JSON output\n- Configuration and `.reach.exs` policy\n- Concepts: dependence graph, control flow, call graph, data flow, effects, OTP\n- Validation and ProgramFacts oracle checks\n- Recipes and contributing notes\n\n## Validation\n\nReach itself is validated with:\n\n```bash\nmix compile --force --warnings-as-errors\nmix ci\n/tmp/reach_validate_canonical_full.sh\nmix docs\nmix hex.build\n```\n\n`mix ci` includes formatting, JS checks, Credo/ExSlop, ExDNA duplication checks, architecture policy, Dialyzer, and tests.\n\n## Credo overlap\n\nA handful of Reach smell patterns overlap with Credo refactoring checks (`MapJoin`, `FilterCount`, `FilterFilter`, `MapInto`, `UnlessWithElse`, `CondStatements`, `ExpensiveEmptyEnumCheck`). Both tools can run together — Reach findings are advisory and never fail the build.\n\n## Acknowledgements\n\nSome structural smell patterns were informed by public [Credence](https://github.com/Cinderella-Man/credence) rules and [Clippy](https://rust-lang.github.io/rust-clippy/) lint categories. Framework-specific smell ideas are also informed by the public [claude-elixir-phoenix](https://github.com/oliver-kriska/claude-elixir-phoenix) rule set. Reach implements them over its own IR/project model and keeps them advisory.\n\n## License\n\nMIT. See [`LICENSE`](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felixir-vibe%2Freach","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felixir-vibe%2Freach","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felixir-vibe%2Freach/lists"}