{"id":47444109,"url":"https://github.com/JuliaDebug/Infiltrator.jl","last_synced_at":"2026-04-06T13:00:57.872Z","repository":{"id":37208672,"uuid":"203810495","full_name":"JuliaDebug/Infiltrator.jl","owner":"JuliaDebug","description":"No-overhead breakpoints in Julia","archived":false,"fork":false,"pushed_at":"2026-03-11T14:26:49.000Z","size":1930,"stargazers_count":482,"open_issues_count":10,"forks_count":25,"subscribers_count":5,"default_branch":"master","last_synced_at":"2026-03-11T19:54:42.650Z","etag":null,"topics":["breakpoint","debugging","julia"],"latest_commit_sha":null,"homepage":"","language":"Julia","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/JuliaDebug.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":null,"dco":null,"cla":null}},"created_at":"2019-08-22T14:21:06.000Z","updated_at":"2026-03-11T14:02:35.000Z","dependencies_parsed_at":"2025-12-20T00:02:19.849Z","dependency_job_id":null,"html_url":"https://github.com/JuliaDebug/Infiltrator.jl","commit_stats":{"total_commits":119,"total_committers":11,"mean_commits":"10.818181818181818","dds":"0.26050420168067223","last_synced_commit":"0be1e7f78c0f41ba8b39aa97e6cef0d8070a6e9a"},"previous_names":[],"tags_count":47,"template":false,"template_full_name":null,"purl":"pkg:github/JuliaDebug/Infiltrator.jl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaDebug%2FInfiltrator.jl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaDebug%2FInfiltrator.jl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaDebug%2FInfiltrator.jl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaDebug%2FInfiltrator.jl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JuliaDebug","download_url":"https://codeload.github.com/JuliaDebug/Infiltrator.jl/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaDebug%2FInfiltrator.jl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31473271,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-06T08:36:52.050Z","status":"ssl_error","status_checked_at":"2026-04-06T08:36:51.267Z","response_time":112,"last_error":"SSL_read: 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":["breakpoint","debugging","julia"],"created_at":"2026-03-23T06:00:59.902Z","updated_at":"2026-04-06T13:00:57.866Z","avatar_url":"https://github.com/JuliaDebug.png","language":"Julia","funding_links":[],"categories":["Binary Analysis and Reverse Engineering"],"sub_categories":["Debugging and Introspection"],"readme":"\u003cdiv align=\"center\"\u003e\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"docs/src/assets/logo-dark.svg\"\u003e\n  \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"docs/src/assets/logo.svg\"\u003e\n  \u003cimg alt=\"Infiltrator Logo\" src=\"docs/src/assets/logo.svg\" width=\"150px\"\u003e\n\u003c/picture\u003e\n\u003c/div\u003e\n\n# Infiltrator.jl\n\n[![CI](https://github.com/JuliaDebug/Infiltrator.jl/actions/workflows/CI.yml/badge.svg)](https://github.com/JuliaDebug/Infiltrator.jl/actions/workflows/CI.yml) [![Codecov](https://codecov.io/gh/JuliaDebug/Infiltrator.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/JuliaDebug/Infiltrator.jl) [![version](https://juliahub.com/docs/Infiltrator/version.svg)](https://juliahub.com/ui/Packages/Infiltrator/ge3PS)\n\n[![docs stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://juliadebug.github.io/Infiltrator.jl/stable) [![docs dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://juliadebug.github.io/Infiltrator.jl/dev)\n\nThis packages provides the `@infiltrate` macro, which acts as a breakpoint with negligible runtime\nperformance overhead.\n\nNote that you cannot access other function scopes or step into further calls. Use an actual debugger\nif you need that level of flexibility.\n\nRunning code that ends up triggering the `@infiltrate` REPL mode via inline evaluation in VS Code\nor Juno can cause issues, so it's recommended to always use the REPL directly.\n\n## `@infiltrate`\n\n```julia\n@infiltrate\n@infiltrate condition::Bool\n```\n\n`@infiltrate` sets an infiltration point.\n\nWhen the infiltration point is hit, it will drop you into an interactive REPL session that\nlets you inspect local variables and the call stack as well as execute arbitrary statements\nin the context of the current local and global scope.\n\nThe optional argument `cond` only enables this infiltration point if it evaluates to `true`, e.g.\n\n```julia\n@infiltrate false # does not infiltrate\n```\n\nYou can also use\n\n```julia\nif isdefined(Main, :Infiltrator)\n  Main.infiltrate(@__MODULE__, Base.@locals, @__FILE__, @__LINE__)\nend\n```\n\nto infiltrate package code without any post-hoc evaluation into the module (because the\nfunctional form does not require Infiltrator to be loaded at compiletime).\n\n## The safehouse\n\nExfiltrating variables (with `@exfiltrate` or by assignment in an `@infiltrate` session) happens by\nassigning the variable to a global storage space (backed by a module); any exfiltrated objects\ncan be directly accessed, via `Infiltrator.store` or its exported aliases `safehouse` or `exfiltrated`:\n\n```julia-repl\njulia\u003e foo(x) = @exfiltrate\nfoo (generic function with 1 method)\n\njulia\u003e foo(3)\n\njulia\u003e safehouse.x # or exfiltrated.x\n3\n\njulia\u003e bar(x, y) = @exfiltrate x y_sum = sum(y)   # selective exfiltration\nbar (generic function with 1 method)\n\njulia\u003e bar(10, [2,5])\n\njulia\u003e safehouse.x\n10\n\njulia\u003e safehouse.y_sum\n7\n```\n\nYou can reset the safehouse with `Infiltrator.clear_store!()`.\n\nYou can also assign a specific module with `Infiltrator.set_store!(mod)`. This allows you to e.g. set the\nbacking module to `Main` and therefore export the contents of the safehouse to the global namespace\n(although doing so is not recommended).\n\n## Usage\n### Scripts and package development\nUsing Infiltrator for debugging packages or scripts requires a little bit of setup.\n\n1. Either your current environment or an environment futher down the [environment stack](https://docs.julialang.org/en/v1/manual/code-loading/#Environment-stacks) must contain Infiltrator.jl. I would recommend putting Infiltrator.jl into your global `@v1.xx` environment so that it is always available.\n2. Load Infiltrator.jl with `using Infiltrator` in the REPL\n3. Load [Revise.jl](https://github.com/timholy/Revise.jl) or use [VS Code's inline evaluation](https://www.julia-vscode.org/docs/stable/userguide/runningcode/) to seamlessly update your package code.\n4. Load your package.\n5. Add `Main.@infiltrate` statements as breakpoints wherever desired.\n6. Run a function that ends up executing the method containing the breakpoint.\n\nThe ordering of steps 4 and 5 is important: loading your package after adding `Main.@infiltrate` statements will\nprevent if from loading, because that macro does not exist during precompilation.\n\nIf you absolutely cannot modfiy your code after loading it initially, then the `infiltrate` function *can* be used\ninstead. An advantage of the macro form is that it will fail tests, so you don't end up committing or merging code\ncontaining infiltration points.\n\n### REPL session\n```julia-repl\njulia\u003e function f(x)\n         out = []\n         for i in x\n           push!(out, 2i)\n           @infiltrate\n         end\n         out\n       end\nf (generic function with 1 method)\n\njulia\u003e f([1,2,3,4,5,6,7,8,9,10])\nInfiltrating f(x::Vector{Int64})\n  at REPL[10]:5\n\ninfil\u003e ?\n  Code entered here is evaluated in the current scope. Changes to local variables are not possible; global variables can only be changed with eval/@eval.\n\n  All assignments will end up in the safehouse.\n\n  The following commands are special cased:\n\n    •  ?: Print this help text.\n\n    •  @trace: Print the current stack trace.\n\n    •  @locals: Print local variables. @locals x y only prints x and y.\n\n    •  @exception: Print the exception that triggered the current @infiltry session, if any.\n\n    •  @exfiltrate: Save all local variables into the store. @exfiltrate x y saves x and y; this variant can also exfiltrate variables defined in the infil\u003e REPL.\n\n    •  @toggle: Toggle infiltrating at this @infiltrate spot (clear all with Infiltrator.clear_disabled!()).\n\n    •  @cond expr: Infiltrate at this @infiltrate spot only if \u003cexpr\u003e evaluates to true (clear all with\n       Infiltrator.clear_conditions!()).\n\n    •  @continue: Continue to the next infiltration point or exit (shortcut: Ctrl-D).\n\n    •  @continue N: Continue and stop at the Nth hit of this infiltration point. If a `@cond` is active, only hits where the condition evaluates to true are counted.\n\n    •  @doc symbol: Get help for symbol (same as in the normal Julia REPL).\n\n    •  @exit: Stop infiltrating for the remainder of this session and exit.\n\n    •  `@abort`: Stop program execution by throwing an `AbortException`.\n\ninfil\u003e @locals\n- out::Vector{Any} = Any[2]\n- i::Int64 = 1\n- x::Vector{Int64} = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n\ninfil\u003e 0//0\nERROR: ArgumentError: invalid rational: zero(Int64)//zero(Int64)\nStacktrace:\n [1] __throw_rational_argerror_zero(T::Type)\n   @ Base ./rational.jl:32\n [2] Rational{Int64}(num::Int64, den::Int64)\n   @ Base ./rational.jl:34\n [3] Rational\n   @ ./rational.jl:39 [inlined]\n [4] //(n::Int64, d::Int64)\n   @ Base ./rational.jl:62\n [5] top-level scope\n   @ none:1\n\ninfil\u003e @toggle\nDisabled infiltration at this infiltration point.\n\ninfil\u003e @toggle\nEnabled infiltration at this infiltration point.\n\ninfil\u003e @cond i \u003e 5\nConditionally enabled infiltration at this infiltration point.\n\ninfil\u003e @continue\n\nInfiltrating f(x::Vector{Int64})\n  at REPL[10]:5\n\ninfil\u003e i\n6\n\ninfil\u003e intermediate = copy(out)\n6-element Vector{Any}:\n  2\n  4\n  6\n  8\n 10\n 12\n\ninfil\u003e @exfiltrate intermediate x\nExfiltrating 2 local variables into the safehouse.\n\ninfil\u003e @exit\n\n10-element Vector{Any}:\n  2\n  4\n  6\n  8\n 10\n 12\n 14\n 16\n 18\n 20\n\n\njulia\u003e safehouse.intermediate\n6-element Vector{Any}:\n  2\n  4\n  6\n  8\n 10\n 12\n\njulia\u003e @withstore begin\n         x = 23\n         x .* intermediate\n       end\n6-element Vector{Int64}:\n  46\n  92\n 138\n 184\n 230\n 276\n```\n\n## Advanced\n### Auto-loading Infiltrator.jl\nInfiltrator loads very fast (~3ms on my machine) and is generally safe to load in `startup.jl`.\n\nIf, for whatever reason, you do not want to unconditionally load Infiltrator in your `startup.jl`,\nyou can use the following convenience macro instead. It will automatically load\nInfiltrator.jl (if it is in your environment stack) and subsequently call `@infiltrate`:\n```julia\nmacro autoinfiltrate(cond=true)\n    pkgid = Base.PkgId(Base.UUID(\"5903a43b-9cc3-4c30-8d17-598619ec4e9b\"), \"Infiltrator\")\n    if !haskey(Base.loaded_modules, pkgid)\n        try\n            Base.eval(Main, :(using Infiltrator))\n        catch err\n            @error \"Cannot load Infiltrator.jl. Make sure it is included in your environment stack.\"\n        end\n    end\n    i = get(Base.loaded_modules, pkgid, nothing)\n    lnn = LineNumberNode(__source__.line, __source__.file)\n\n    if i === nothing\n        return Expr(\n            :macrocall,\n            Symbol(\"@warn\"),\n            lnn,\n            \"Could not load Infiltrator.\")\n    end\n\n    return Expr(\n        :macrocall,\n        Expr(:., i, QuoteNode(Symbol(\"@infiltrate\"))),\n        lnn,\n        esc(cond)\n    )\nend\n```\n\n## Related projects\n\n- [`@exfiltrate` for Python](https://github.com/NightMachinary/PyExfiltrator)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJuliaDebug%2FInfiltrator.jl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FJuliaDebug%2FInfiltrator.jl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJuliaDebug%2FInfiltrator.jl/lists"}