[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-82740":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":14,"subscribersCount":14,"size":14,"stars1d":15,"stars7d":16,"stars30d":17,"stars90d":14,"forks30d":14,"starsTrendScore":18,"compositeScore":19,"rankGlobal":9,"rankLanguage":9,"license":20,"archived":21,"fork":21,"defaultBranch":22,"hasWiki":23,"hasPages":21,"topics":24,"createdAt":9,"pushedAt":9,"updatedAt":25,"readmeContent":26,"aiSummary":27,"trendingCount":14,"starSnapshotCount":14,"syncStatus":15,"lastSyncTime":28,"discoverSource":29},82740,"PseudoForge","kernullist\u002FPseudoForge","kernullist","An IDA Pro \u002F Hex-Rays plugin that turns noisy pseudocode into reviewable, kernel-aware cleanup artifacts",null,"Python",118,12,3,0,2,19,52,11,62.04,"MIT License",false,"main",true,[],"2026-06-12 04:01:38","# PseudoForge\n\nPseudoForge is an IDA Pro \u002F Hex-Rays plugin that turns noisy pseudocode into reviewable, kernel-aware cleanup artifacts.\n\nThe core direction is deterministic-first. PseudoForge does not let an LLM rewrite arbitrary code. It builds a validated `CleanPlan` from deterministic analysis, optional data-only rules, and optional LLM rename suggestions, then writes preview\u002Fexport artifacts that can be compared against the original pseudocode. IDB writes remain limited to user-selected, validator-gated local and argument renames.\n\nAll repository documentation is written in English. Generated comments, logs, rule text, and examples should also stay ASCII-only unless a file has an explicit reason to use another character set.\n\n## Preview\n\nThe left side is raw Hex-Rays pseudocode. The right side is the PseudoForge preview.\n\nAnimated demo of the interactive IDA preview workflow:\n\n![PseudoForge interactive IDA preview demo](screenshots\u002FPseudoForge-demo.gif)\n\nStatic preview examples:\n\n![PseudoForge preview comparing raw Hex-Rays pseudocode with kernel-aware cleaned output](screenshots\u002Fexample.png)\n\nThe second preview shows no-symbol OB callback cleanup with inferred `LIST_ENTRY` record types and `CONTAINING_RECORD`-based traversal.\n\n![PseudoForge preview of no-symbol OB callback cleanup with inferred LIST_ENTRY records](screenshots\u002Fexample2.png)\n\nThe third preview shows the `PfKernelPattern` IOCTL handler cleanup, including IRP dispatch naming, `IO_STACK_LOCATION.Parameters.DeviceIoControl` field rendering, `SystemBuffer` union alias cleanup, NTSTATUS names, and decoded `CTL_CODE(...)` case comments.\n\n![PseudoForge preview of PfKernelPattern IOCTL handler cleanup with decoded CTL_CODE comments](screenshots\u002Fexample3.png)\n\nThe fourth preview shows the dockable side-by-side review panel with raw\nHex-Rays pseudocode on the left, cleaned PseudoForge output on the right,\ncompact status\u002Fsearch rows, synchronized search navigation, and highlighted\nmatches.\n\n![PseudoForge side-by-side raw and cleaned pseudocode preview with search highlighting](screenshots\u002Fexample4.png)\n\n## Decompiler Output Dependency\n\nPseudoForge works on Hex-Rays pseudocode output. Its cleanup quality depends heavily on the quality of the initial decompilation.\n\nBetter Hex-Rays output usually produces better PseudoForge output. Type information, function prototypes, structure recovery, imported kernel symbols, PDB\u002Ftype library availability, and correct calling conventions all improve deterministic matching and reduce noisy casts.\n\nPseudoForge does not recover semantics that are completely absent from the decompiler output, and it does not treat LLM suggestions as authoritative rewrites. LLM assist remains optional and must pass deterministic validation. Preview\u002Fexport artifacts are the primary output; IDB writes remain limited to explicitly selected, validator-gated rename operations.\n\nFor best results:\n\n- Let IDA finish analysis before previewing or exporting PseudoForge output.\n- Load relevant PDBs, type libraries, WDK headers, and kernel type information when available.\n- Fix obviously wrong function prototypes and calling conventions before cleanup.\n- Prefer symbol and type recovery over text-only cleanup.\n- Review inferred structure rewrites, especially when fixed offsets are converted into semantic fields.\n\n## Quick Start\n\n1. Use IDA Pro 9.x or newer with Hex-Rays for the interactive plugin path.\n2. Copy `pseudoforge.py`, `ida-plugin.json`, and `ida_pseudoforge\u002F` into the IDA user plugin directory.\n3. Open a pseudocode view and run `Edit\u002FPseudoForge\u002FAnalyze current function`.\n4. Review the generated `\u003Cinput>.forge` section or export bundle before applying any IDB rename.\n5. For offline smoke testing, run:\n\n```powershell\npython -B .\\tools\\pseudoforge_cli.py .\\samples\\pseudocode\\NtSetSystemInformation_switch_renamed.cpp --out $env:TEMP\\pseudoforge_cli_smoke\n```\n\nKey documentation:\n\n- [pseudoforge_implementation_status.md](pseudoforge_implementation_status.md): current implemented scope and validation history.\n- [pseudoforge_improvement_plan.md](pseudoforge_improvement_plan.md): prioritized improvement backlog from the current code and documentation review.\n- [ida_pseudocode_refactor_plugin_design.md](ida_pseudocode_refactor_plugin_design.md): overall product and architecture design.\n- [deterministic_rules_matching_engine_design.md](deterministic_rules_matching_engine_design.md): deterministic JSON rule engine design.\n- [samples\u002Fkernel_pattern_driver\u002FREADME.md](samples\u002Fkernel_pattern_driver\u002FREADME.md): WDK sample corpus for kernel-pattern analysis.\n\n## Versioning\n\nCurrent plugin version: `0.1.1`.\n\nThe runtime version source is `ida_pseudoforge\u002Fversion.py`. The `ida-plugin.json` manifest version must match it; the unit suite enforces this parity so plugin packaging and runtime reporting do not drift.\n\nWays to check the installed\u002Fcurrent version:\n\n```powershell\npython -B .\\tools\\pseudoforge_cli.py --version\npython -B .\\tools\\pseudoforge_free_cli.py --version\n```\n\nInside IDA, run `Edit\u002FPseudoForge\u002FShow settings`. Preview\u002Fexport headers, switch outlines, aggregate `.forge` sections, and IDA Free CLI JSON reports also include the version.\n\nRelease packaging bumps the patch version by default, updates `ida_pseudoforge\u002Fversion.py`, `ida-plugin.json`, and the current-version lines in the docs, then writes an installable zip named with the new version:\n\n```powershell\npython -B .\\tools\\release_pseudoforge.py\n```\n\nThe default archive path is:\n\n```text\nrelease\\PseudoForge-\u003Cnew-version>.zip\n```\n\nUseful release options:\n\n```powershell\npython -B .\\tools\\release_pseudoforge.py --dry-run\npython -B .\\tools\\release_pseudoforge.py --bump minor\npython -B .\\tools\\release_pseudoforge.py --version 0.2.0\npython -B .\\tools\\release_pseudoforge.py --no-version-bump\n```\n\n## Current Implementation Status\n\nThe current implementation is an MVP+ slice. The core engine, offline CLI, deterministic rules engine, headless IDA batch path, and interactive IDA plugin load\u002Fcapture\u002Fexport\u002Faction workflow have been validated.\n\nImplemented:\n\n1. Current-function Hex-Rays pseudocode capture.\n2. Parameter and local rename plan generation from prototypes and usage patterns.\n3. Rename validation for collisions, reserved words, invalid identifiers, and weak speculative names.\n4. Dispatcher case recovery from `vX = dispatcher - constant` chains.\n   - Chained delta temporaries can be rendered as profile-backed enum comparisons.\n   - Stale delta temporaries reused after large branch bodies are kept unchanged.\n5. Native top-level `switch(dispatcher)` case and single-return body extraction.\n6. Nested switch depth tracking so inner cases are not mixed into the top-level dispatcher.\n7. Cleanup label classification.\n8. Kernel driver semantics pass.\n   - NTSTATUS literal normalization in returns and status assignments.\n   - Profile-backed `0xC???????` NTSTATUS error literals in 4-byte local assignments and `_DWORD` stores.\n   - Deterministic LIST_ENTRY record\u002Flink\u002Ftail naming that outranks generic LLM suggestions.\n   - LIST_ENTRY unlink\u002Finsert-tail pattern hints.\n   - ERESOURCE, critical region, pool allocation, object reference, and failfast insights.\n   - Pool tag decoding such as `0x54465241` to `ARFT`.\n9. Profile-backed NTSTATUS, `SYSTEM_INFORMATION_CLASS`, and `PROCESSINFOCLASS` names.\n   - 25H2-range `SYSTEM_INFORMATION_CLASS` and `PROCESSINFOCLASS` profile coverage.\n   - Preview-only canonical prototypes for `NtSetSystemInformation` and `NtSetInformationProcess`.\n10. Recovered dispatcher output as an auxiliary switch-case outline appended after normalized original pseudocode.\n11. Generated pseudocode style normalization.\n   - Opening braces on the next line.\n   - Mandatory braces for `if`, `else`, `for`, and `while`.\n   - Standalone `else`.\n   - Guard flattening after terminating branches.\n   - No forced `do { } while (false)` conversion.\n12. Cleaned pseudocode preview in an IDA native custom viewer.\n13. Aggregate `\u003Cinput>.forge` analysis file beside the analyzed binary.\n14. Export bundle for cleaned pseudocode, switch outline, rename map, flow report, and rule report.\n15. Action for applying selected local and argument renames to the IDB.\n16. IDA Output progress logging with file-backed trace logs.\n17. Offline CLI smoke path that does not require IDA.\n18. Multi-provider optional LLM rename assist inside IDA.\n19. Optional offline CLI LLM rename assist.\n20. Synchronized warning counts between `.forge` metadata and preview headers.\n21. Stable `.forge` path\u002Fstring escaping and current-function section preview.\n22. Headless IDA batch analysis over `.i64` \u002F `.idb` functions.\n23. WDK-based kernel driver test corpus under `samples\u002Fkernel_pattern_driver`.\n24. Deterministic rules matching engine v1.\n   - Data-only JSON rule pack loader.\n   - Builtin, project-local, and user-global rule directories.\n   - Regex and assignment-based rename rules.\n   - Semantic comment rules.\n   - Fail-closed validator CLI.\n   - Per-function rule report export.\n25. Deterministic rules matching engine v2 preview\u002Freport phases.\n   - Preview-only `call_arg_rewrite` reports.\n   - Preview-only `text_rewrite` reports with semantic comment gates and span\n     conflict detection.\n   - Preview-only `flow` reports gated by recovered dispatcher case evidence.\n26. IDA analysis completion summaries include deterministic rule diagnostic\n    counts.\n27. Export summaries and IDA Free result summaries include deterministic rule\n    diagnostic counts plus rule load and validation error details.\n28. IDA LLM model discovery uses a non-blocking background refresh cache so\n    configuration dialogs can open with static or cached model lists.\n29. IDA analysis preview can try an experimental dockable side-by-side raw vs\n    cleaned review panel through the persisted `Configure preview mode` setting\n    or temporary `PSEUDOFORGE_PREVIEW_BACKEND` override, with a compact\n    warning\u002Frule summary row, synchronized line search, and side-by-side Qt\n    syntax highlighting that reuses the preview token-role classifier while\n    preserving the existing `simplecustviewer_t` fallback.\n30. IDA analyze\u002Fexport\u002Fapply tasks support cooperative cancellation checkpoints,\n    and headless IDA batch runs can stop at a cancel-file boundary while writing\n    per-function start progress records.\n31. Generic runtime helper aliasing can classify strongly evidenced no-PDB\n    `sub_*` memory-fill and memory-move helpers and render caller sites as\n    standard `memset` or `memmove` calls without renaming helper definitions.\n32. IDA batch and interactive analysis can probe direct helper callees on\n    demand, so helper aliases do not require users to analyze every function\n    first.\n33. Raw-vs-cleaned compare directories can be scored with a corpus-agnostic\n    quality scorer that reports remaining Hex-Rays artifacts and positive\n    semantic recovery signals.\n34. Claude CLI providers default to a hook-isolated print-mode command\n    (`--setting-sources project,local`) and old default templates are migrated\n    on load; LLM failures are summarized in IDA Output before deterministic\n    fallback continues.\n\nStill pending:\n\n1. Full switch body reconstruction for shared and fallthrough branches.\n2. True object-level ctree rename application beyond the current identity preflight gates.\n3. Broader deterministic rule parity migration beyond report-only phases.\n4. Wider profile coverage from real target builds.\n\nDetailed implementation tracking lives in [pseudoforge_implementation_status.md](pseudoforge_implementation_status.md).\n\n## Requirements\n\nCore plugin:\n\n- Windows\n- IDA Pro 9.x or newer\n- Hex-Rays decompiler\n- IDA-bundled Python 3\n- No external Python packages for core operation\n\nIDA Pro 7.6 or newer may be able to run PseudoForge, but that compatibility path has not been verified yet. Treat IDA 9.x as the supported requirement until older versions are tested directly.\n\nOffline CLI:\n\n- Validated with Python 3.11\n- Standard library only\n\nIDA Free:\n\n- Not supported as an interactive PseudoForge plugin target.\n- IDA Free does not provide the IDAPython and local Hex-Rays APIs required by the plugin actions.\n- Supported only through the offline CLI workflow where copied or saved cloud-decompiled pseudocode text is processed outside IDA.\n- The IDA Free CLI path does not modify an IDB and does not apply renames back into IDA.\n\nOptional LLM rename assist:\n\n- OpenAI-compatible `\u002Fchat\u002Fcompletions` endpoint\n- OpenRouter `\u002Fchat\u002Fcompletions` endpoint\n- DeepSeek OpenAI-compatible endpoint\n- ChatGPT OAuth via Codex CLI, Codex CLI, Claude login via Claude CLI, or Claude CLI command bridge\n- IDA configuration through `Configure LLM rename assist`\n- Environment variables or command-line options for offline CLI\n- Not required for deterministic analysis\n\n## File Layout\n\n```text\npseudoforge.py\nida-plugin.json\nida_pseudoforge\u002F\n  version.py\n  config.py\n  core\u002F\n    capture.py\n    deterministic\u002F\n      context.py\n      emitters.py\n      engine.py\n      loader.py\n      schema.py\n      validators.py\n      matchers\u002F\n        regex.py\n    export_bundle.py\n    flow_recovery.py\n    forge_store.py\n    helper_aliases.py\n    ioctl.py\n    kernel_api.py\n    kernel_rewrites.py\n    normalize.py\n    kernel_semantics.py\n    lvar_analysis.py\n    cleanup_rewriter.py\n    offline_input.py\n    pattern_renames.py\n    llm_assist.py\n    quality_score.py\n    rule_diagnostics.py\n    validation.py\n    render.py\n    render_cleanup.py\n    render_callbacks.py\n    render_call_args.py\n    render_dispatcher.py\n    render_driver_entry.py\n    render_flow.py\n    render_header.py\n    render_ioctl.py\n    render_kernel_hints.py\n    render_labels.py\n    render_literals.py\n    render_ntset.py\n    render_signatures.py\n    render_status.py\n    render_style.py\n    render_warnings.py\n    render_zw.py\n    plan_schema.py\n    api_semantics.py\n  profiles\u002F\n    loader.py\n    profiles_manifest.json\n    kernel_api.json\n    kernel_api_overrides.json\n    status_codes.json\n    process_information_class.json\n    system_information_class.json\n  rules\u002F\n    builtin\u002F\n      kernel_comments.json\n      local_renames.json\n  models\u002F\n    base.py\n    cli_provider.py\n    model_discovery.py\n    openai_compatible.py\n    prompting.py\n    provider_factory.py\n    provider_registry.py\n    subprocess_utils.py\n  logging.py\n  ida\u002F\n    action_registry.py\n    analysis_state.py\n    async_runner.py\n    plugin.py\n    actions.py\n    decompiler.py\n    llm_config_dialog.py\n    apply_changes.py\n    ui_preview.py\n    thread_helpers.py\ntools\u002F\n  build_kernel_api_profile.py\n  build_status_codes_profile.py\n  empty_llm_rename_provider.py\n  profile_load_smoke.py\n  pseudoforge_cli.py\n  pseudoforge_free_console.py\n  pseudoforge_free_cli.py\n  pseudoforge_ida_batch.py\n  pseudoforge_ida_identity_apply_smoke.py\n  release_pseudoforge.py\n  run_pseudoforge_ida_batch.ps1\n  score_pseudoforge_quality.py\n  summarize_pseudoforge_ida_batch.py\n  validate_pseudoforge_rules.py\nsamples\u002F\n  pseudocode\u002F\n    NtSetSystemInformation_switch_renamed.cpp\n  kernel_pattern_driver\u002F\ntests\u002F\n  test_export_bundle.py\n  test_forge_store.py\n  test_helper_aliases.py\n  test_ida_batch.py\n  test_ida_identity_apply_smoke.py\n  test_ida_plugin_safety.py\n  test_kernel_api_profile_builder.py\n  test_llm_cli_provider.py\n  test_llm_config.py\n  test_llm_rename_filters.py\n  test_logging.py\n  test_plan_builder.py\n  test_profile_load_smoke.py\n  test_profile_loader.py\n  test_pseudoforge_free_cli.py\n  test_quality_score.py\n  test_rename_heuristics.py\n  test_render_callbacks.py\n  test_render_call_args.py\n  test_render_cleanup.py\n  test_render_dispatcher.py\n  test_render_driver_entry.py\n  test_render_flow.py\n  test_render_header.py\n  test_render_ioctl.py\n  test_render_kernel_hints.py\n  test_render_labels.py\n  test_render_literals.py\n  test_render_memory.py\n  test_render_ntset.py\n  test_render_snapshots.py\n  test_render_signatures.py\n  test_render_status.py\n  test_render_style.py\n  test_render_warnings.py\n  test_render_zw.py\n  test_release_pseudoforge.py\n  test_rule_context.py\n  test_rule_diagnostics.py\n  test_rule_engine.py\n  test_rule_integration.py\n  test_rule_pack_validator.py\n  test_ui_preview.py\n```\n\n## Installation\n\nCopy the plugin entrypoint, plugin manifest, and package directory into the IDA user plugin directory:\n\n```text\npseudoforge.py\nida-plugin.json\nida_pseudoforge\u002F\n```\n\nThe common Windows user plugin directory is:\n\n```text\n%APPDATA%\\Hex-Rays\\IDA Pro\\plugins\n```\n\nPowerShell copy example:\n\n```powershell\n$pluginDir = Join-Path $env:APPDATA \"Hex-Rays\\IDA Pro\\plugins\"\nNew-Item -ItemType Directory -Force $pluginDir | Out-Null\n\nCopy-Item .\\pseudoforge.py -Destination $pluginDir -Force\nCopy-Item .\\ida-plugin.json -Destination $pluginDir -Force\nCopy-Item .\\ida_pseudoforge -Destination $pluginDir -Recurse -Force\n```\n\nTo confirm the IDA user directory, run this in the IDA Python console:\n\n```python\nimport ida_diskio\nprint(ida_diskio.get_user_idadir())\n```\n\nDuring development, a symlink or junction install is usually faster:\n\n```powershell\n$pluginDir = Join-Path $env:APPDATA \"Hex-Rays\\IDA Pro\\plugins\"\nNew-Item -ItemType Directory -Force $pluginDir | Out-Null\n\nNew-Item -ItemType SymbolicLink -Path (Join-Path $pluginDir \"pseudoforge.py\") -Target (Resolve-Path .\\pseudoforge.py) -Force\nNew-Item -ItemType SymbolicLink -Path (Join-Path $pluginDir \"ida-plugin.json\") -Target (Resolve-Path .\\ida-plugin.json) -Force\nNew-Item -ItemType Junction -Path (Join-Path $pluginDir \"ida_pseudoforge\") -Target (Resolve-Path .\\ida_pseudoforge) -Force\n```\n\nIf symlink creation is blocked by Windows policy, use the copy method.\n\n## IDA Usage\n\n1. Restart IDA.\n2. Open the target binary.\n3. Open the Hex-Rays pseudocode view.\n4. Confirm that `Edit\u002FPseudoForge` is visible.\n5. Run an action on the target function.\n\nMenu:\n\n```text\nEdit\u002FPseudoForge\u002F\n  Analyze current function\n  Show current analysis result\n  Analyzed functions...\n  Export cleaned pseudocode\n  Cancel current operation\n  Configure LLM rename assist\n  Configure profile directory\n  Configure preview mode\n  Show settings\n  Advanced\u002F\n    Apply selected renames to IDB\n```\n\nPseudocode view context menu:\n\n```text\nPseudoForge\u002F\n  Analyze current function\n  Show current analysis result\n  Analyzed functions...\n  Export cleaned pseudocode\n  Cancel current operation\n  Configure LLM rename assist\n  Configure profile directory\n  Configure preview mode\n  Show settings\n  Advanced\u002F\n    Apply selected renames to IDB\n```\n\nHotkeys:\n\n```text\nCtrl+Alt+F        Analyze current function\nCtrl+Alt+P        Show current analysis result\nCtrl+Alt+Shift+P  Analyzed functions...\nCtrl+Alt+Shift+F  Export cleaned pseudocode\nCtrl+Alt+Shift+V  Configure preview mode\n```\n\n### Actions\n\n`Analyze current function` decompiles the current function, builds the rename plan, flow outline, cleanup classification, deterministic rule report, and warnings, then updates the function section in `\u003Cinput>.forge`. It does not modify the IDB.\n\n`Show current analysis result` opens only the cached `.forge` section whose function start EA matches the current pseudocode cursor. It does not decompile, invoke an LLM, run analysis, or refresh the `.forge` file. If side-by-side preview is enabled, it uses the current in-memory raw Hex-Rays pseudocode when available, otherwise it reuses the raw pseudocode persisted in the `.forge` section. Legacy `.forge` sections that predate stored raw pseudocode warn and open the cleaned section only until the function is analyzed once with the current PseudoForge version. If the current function has not been analyzed yet, it asks the user to run `Analyze current function` first. `Copy all` and `Save as...` operate on that selected section.\n\n`Analyzed functions...` opens a chooser built from cached `.forge` function-section markers. It avoids opening the full aggregate `.forge` as the primary UI, which keeps navigation usable after many functions have been analyzed.\n\n`Export cleaned pseudocode` analyzes the current function and writes a review\u002Faudit bundle. Its main purpose is to freeze a PseudoForge result outside the IDA UI so the cleaned pseudocode, rename plan, flow report, and rule report can be shared, diffed, regression-tested, and inspected later. It writes to `pseudoforge_out` beside the IDB when possible and does not modify the IDB.\n\n`Cancel current operation` requests cooperative cancellation for the active analyze, export, or apply-preparation task. Cancellation is checked at safe phase boundaries; an in-flight Hex-Rays decompile or LLM provider call may finish before the task stops.\n\n`Advanced\u002FApply selected renames to IDB` analyzes the function if needed, shows a rename chooser, refuses stale sessions when the current function changed, and applies only user-selected local or argument renames that pass final preflight through `ida_hexrays.rename_lvar()`. This path is intentionally separate from preview\u002Fexport.\n\n`Configure LLM rename assist` stores optional LLM settings in `\u003CIDA user directory>\\pseudoforge_config.json`. HTTP provider API keys are stored per provider under `credentials` and are prompted only when an enabled provider needs a missing key.\n\n`Configure profile directory` stores an optional profile root in `\u003CIDA user directory>\\pseudoforge_config.json`.\n\n`Configure preview mode` stores the preferred preview backend in `\u003CIDA user directory>\\pseudoforge_config.json`.\n\nIf the custom submenu is hidden by an IDA layout\u002Fplugin-menu issue, run\n`Edit\u002FPlugins\u002FPseudoForge` or press `Ctrl+Alt+Shift+V`; both open the preview\nmode configuration fallback.\n\n`Show settings` displays the current plugin version, config path, profile status, preview mode, and LLM status. API keys are masked.\n\n### Preview Behavior\n\n- The preview first shows normalized original pseudocode.\n- Functions with recovered dispatcher information append an auxiliary switch-case outline.\n- The auxiliary outline summarizes nested if\u002Felse dispatcher chains as switch cases.\n- Only single-statement returns and complete local branch slices are expanded in the outline.\n- Complex shared or fallthrough bodies point back to the normalized original pseudocode instead of emitting misleading fragments.\n- Native switches already present in the normalized original pseudocode are not duplicated in the auxiliary outline.\n- Viewer lines use IDA color tag syntax highlighting where practical; large previews automatically fall back to plain text.\n- Side-by-side dockable panes use Qt syntax highlighting where practical, reuse\n  the same token-role classifier as the simple preview, and fall back to plain\n  text when Qt highlighter APIs are unavailable.\n- Side-by-side search highlights every matched occurrence in both panes and\n  uses a stronger highlight for the active `Prev`\u002F`Next` match.\n- New `.forge` function sections persist raw Hex-Rays pseudocode in an encoded\n  comment block so cached side-by-side preview can be reopened without rerunning\n  analysis.\n- `.forge`, `Copy all`, and `Save as...` output remain plain text without color tags.\n- Set `PSEUDOFORGE_DISABLE_PREVIEW_HIGHLIGHT=1` before launching IDA to isolate syntax-highlight issues.\n- Run `Edit\u002FPseudoForge\u002FConfigure preview mode` and select\n  `Side-by-side dockable preview` to persist the experimental dockable\n  raw-vs-cleaned review panel in `pseudoforge_config.json`. If IDA `PluginForm`\n  or Qt widgets are unavailable, PseudoForge warns with the fallback reason and\n  opens the existing simple custom viewer. The dockable backend accepts PyQt5,\n  PyQt6, PySide6, and PySide2 module layouts when IDA exposes them.\n- `PSEUDOFORGE_PREVIEW_BACKEND=side_by_side` remains available as a temporary\n  override before launching IDA. Set it to `simple` to temporarily force the\n  simple custom viewer even when the saved config enables side-by-side preview.\n- Right-click in the preview for `PseudoForge\u002FCopy all`, `PseudoForge\u002FSave as...`, and `PseudoForge\u002FAnalyzed functions...`.\n- `PseudoForge\u002FAnalyzed functions...` and the top-level `Analyzed functions...` action parse `.forge` markers and open a chooser of all analyzed sections.\n- Function-section `Save as...` defaults to `PseudoForge__\u003Ctarget>__\u003Cfunction>_0x\u003CEA>.cpp`.\n- `Copy all` uses the Windows Clipboard API with `CF_UNICODETEXT`; it does not shell out or rely on a Qt clipboard.\n- Clipboard status is written to `%TEMP%\\pseudoforge_clipboard\\copy_all.log`.\n\n### Kernel Driver Cleanup\n\n- Casted NTSTATUS returns such as `return (unsigned int)-1073741727;` can render as `STATUS_PRIVILEGE_NOT_HELD`.\n- Status accumulator assignments such as `status = 0x40000000;` can render as `STATUS_OBJECT_NAME_EXISTS`.\n- Profile-backed `0xC???????` NTSTATUS error literals in 4-byte local assignments and `_DWORD` stores render symbolically, for example `v16 = STATUS_INSUFFICIENT_RESOURCES;`.\n- Wider stores keep the raw literal unless there is stronger type evidence.\n- `status_codes.json` is generated from WDK `ntstatus.h`; low wait\u002Fsuccess aliases are excluded by default except `STATUS_SUCCESS` and `STATUS_PENDING`.\n- Direct `return 0` becomes `STATUS_SUCCESS` only under strong NTSTATUS return evidence such as an explicit `NTSTATUS` prototype, a known signature override, or an `Nt*` \u002F `Zw*` native API name.\n- LLM-only `status` renames do not make `status = 0` become `STATUS_SUCCESS`; success assignments require strong NTSTATUS context or a deterministic kernel-status accumulator.\n- LIST_ENTRY walks, unlink, and insert-tail patterns can produce role-centered names such as `providerRecord`, `providerLink`, `nextLink`, `previousLink`, and `tailLink`.\n- Deterministic kernel names outrank generic LLM suggestions.\n- LLM local and argument renames prefer lowerCamel names. PascalCase LLM names are skipped because they can look like authoritative types or fields.\n- DriverEntry-style setup can recover lowerCamel `driverObject`, `registryPath`, `status`, `extension`, `deviceObject`, `deviceName`, and `majorIndex` names without relying on LLM suggestions.\n- Strong DriverEntry evidence can render the preview signature as `NTSTATUS __fastcall DriverEntry(PDRIVER_OBJECT driverObject, PUNICODE_STRING registryPath)` while keeping IDB writes preview-only.\n- Driver dispatch table initialization can render `IRP_MJ_MAXIMUM_FUNCTION`, `IRP_MJ_CREATE`, `IRP_MJ_CLOSE`, and `IRP_MJ_DEVICE_CONTROL`.\n- Driver device flags can render `DO_BUFFERED_IO` and `DO_DEVICE_INITIALIZING`, and `IoCreateDevice` device characteristics can render `FILE_DEVICE_SECURE_OPEN`.\n- Unknown or vendor `DEVICE_TYPE` values, for example `0x8337u`, stay as literals unless a trusted binary\u002Fprofile source proves a standard `FILE_DEVICE_*` name. PseudoForge does not infer original source macro names.\n- IOCTL dispatcher case constants can be annotated with exact `CTL_CODE(DeviceType, Function, Method, Access)` bitfield decoding, including `METHOD_BUFFERED`, while preserving Hex-Rays integer suffixes and without inventing original `IOCTL_*` macro names.\n- IRP dispatch handlers can render preview signatures as `NTSTATUS __fastcall Name(PDEVICE_OBJECT deviceObject, PIRP irp)` once IRP completion or `IoStatus` evidence identifies the handler.\n- No-PDB dispatch handlers can still recover `deviceObject` and `irp` when the second parameter is completed through `IofCompleteRequest(...)`, including casted forms such as `(IRP *)a2`.\n- `IO_STACK_LOCATION` index rewrites are union-arm gated. `Parameters.DeviceIoControl.*` is emitted only when IRP dispatch evidence and DeviceControl `IoControlCode` stack-index evidence are present; other IRP major-function paths keep raw indexing until their own union arm is identified.\n- IRP dispatch body cleanup can render `deviceObject->DeviceExtension`, `NTSTATUS status`, and `return status;` without requiring DeviceControl-specific evidence.\n- METHOD_BUFFERED-only DeviceControl dispatchers can render the `AssociatedIrp.MasterIrp` union alias as `AssociatedIrp.SystemBuffer` with a `PVOID` local type, but only when `IoControlCode` is proven to come from the DeviceControl stack location. Mixed methods, METHOD_NEITHER cases, or IOCTL-like switches without stack evidence keep the original union alias.\n- LLM-proposed names such as `ioControlCode` or `ioStackLocation` do not force a DeviceControl union arm when the function is not an IRP dispatch path.\n- Device-control dispatchers can recover `deviceObject`, `irp`, `ioStackLocation`, `ioControlCode`, `outputBufferLength`, and `inputBufferLength` from usage. The stack-location variable does not need to already be named `ioStackLocation`.\n- IRP completion tails that set `IoStatus`, call `IofCompleteRequest`, and return status can be labeled as `CompleteIrp` instead of staying as unknown labels.\n- Device-control display warnings suppress resolved buffered\u002FSystemBuffer and dispatch-signature cautions once deterministic IOCTL and IRP evidence has already proved the rewrite.\n- DriverEntry device-extension offset usage can produce a preview-only `INFERRED_DRIVER_DEVICE_EXTENSION` and field access for common initialization, cleanup, work-item, registry-path, lookaside, timer, DPC, rundown, and resource fields.\n- Inferred device-extension structs do not authorize reconstructing original `sizeof(...)` source expressions. Allocation and whole-extension zeroing sizes remain as Hex-Rays literals unless there is direct evidence.\n- DriverEntry display warnings suppress routine LLM sub-function rename guesses and redundant `DeviceExtension` wording once deterministic DriverEntry\u002Fdevice-extension evidence has been recovered.\n- Function pointers resolved through `MmGetSystemRoutineAddress` can use WDK profile metadata when the routine string or function-pointer variable name matches a profiled API and the call arity matches. The preview keeps the indirect call form and adds a `resolved indirect call` comment instead of rewriting it into a direct import-style call.\n- Callback registration toggles that combine process, image, thread, and object callbacks can recover `deviceExtension`, `enable`, callback status locals, `OB_FLT_REGISTRATION_VERSION`, and `OB_OPERATION_REGISTRATION` field assignments from Hex-Rays `_QWORD[4]` stack arrays.\n- Configuration Manager registry callback probes can recover `callbackContext`, `majorVersion`, `minorVersion`, `callbackCookie`, `altitudeString`, `registerExStatus`, and `registerStatus`, while rendering successful `CmRegisterCallback(Ex)` checks with `NT_SUCCESS(...)`.\n- Memory Manager probe functions that combine `MmGetSystemRoutineAddress`, `MmCopyMemory`, MDL setup, noncached memory, and contiguous memory allocation can recover routine-name, buffer, MDL, byte-count, and physical-address locals. Reused probe sinks get neutral names instead of a single stale API role, and preview cleanup can suppress write-only scratch captures while preserving probed calls as `(void)Call(...)`. Generic cleanup also normalizes scalar out-parameter arrays, single-assignment pointer aliases, unrolled wide-array copies, and same-named struct-field locals by usage pattern, while `MmCopyMemory` flags render as `MM_COPY_MEMORY_PHYSICAL` or `MM_COPY_MEMORY_VIRTUAL`.\n- Strongly evidenced no-PDB runtime helper calls can render as `memset` or\n  `memmove` at caller sites. Exact local-array zero fills can use\n  `sizeof(localArray)`, while pointer targets keep explicit byte counts.\n- Zw API corpus\u002Fprobe functions that exercise object, registry, token, and file calls can recover handle, status, object-attribute, timeout, IO-status, value-name, and shared info-buffer roles. Preview rendering keeps the calls intact while normalizing `OBJECT_ATTRIBUTES` size, `OBJ_*` flags, `NtCurrentProcess()`, `NtCurrentThread()`, and successful status checks.\n- Confident record layout evidence can simplify offset arithmetic into preview-only `CONTAINING_RECORD(...)` forms.\n- Known OB pre-operation callbacks simplify raw offset loads such as `*(_DWORD *)(*(_QWORD *)(preOperationInfo + 32) + 4LL)` and typed-array offset loads such as `*(_DWORD *)(*((_QWORD *)preOperationInfo + 4) + 4LL)` into typed `preOperationInfo->Parameters->...OriginalDesiredAccess` access.\n- No-symbol OB pre-operation callbacks with a suspicious `POB_PRE_OPERATION_CALLBACK` second parameter can be normalized to `POB_PRE_OPERATION_INFORMATION preOperationInfo` when field-use evidence matches the callback information layout.\n- OB pre-operation private LIST_ENTRY records and event records can receive preview-only inferred record types when allocation size, list walk shape, and field-write evidence all match. Confirmed record loops are rendered with a separate `LIST_ENTRY *` iterator and `CONTAINING_RECORD(...)`.\n- Identified LIST_ENTRY heads can become aliases such as `providerListHead = (LIST_ENTRY *)&ExpFirmwareTableProviderListHead`.\n- Verified neighboring-link checks can render as `RemoveEntryList(providerLink)` and `InsertTailList(providerListHead, newProviderLink)`.\n- Self-linked LIST_ENTRY initialization can render as `InitializeListHead(newProviderLink)`.\n- Suspicious call targets are preserved with warning comments; uncertain targets are not replaced with different API names.\n- Semantic labels such as `CorruptListEntry`, `InvalidParameter`, and `Cleanup` are column-zero labels.\n- Duplicate semantic labels receive stable suffixes such as `InvalidParameter_17`.\n- Safe tail-label hoisting separates error\u002Ffailfast paths from normal cleanup returns.\n- `Flow rewrites` counts dispatcher\u002Fswitch recovery only. Kernel semantic substitutions are counted under `Kernel semantic rewrites`.\n- Recovered switch outlines and flow reports include per-case body states,\n  source line anchors, and shared-tail labels. Complete local branch slices can\n  be expanded when they end in a local return; shared, partial, or complex\n  bodies stay in the normalized original pseudocode.\n- TraceLogging and C++ template wrapper functions are not promoted to recovered switch outlines.\n- Kernel rewrite patterns belong in `core\u002Fkernel_rewrites.py`, either in `KernelRewriteRule` entries or narrow helper passes. Avoid adding individual kernel patterns directly to `render.py`.\n- Kernel rewrite rules should be gated by `Kernel insights` comment kind and confidence where applicable.\n- WDK-backed API parameter metadata can render calls like `ExAllocatePool2(0x100uLL, 0x28uLL, 0x54465241u)` as `ExAllocatePool2(POOL_FLAG_PAGED, 0x28uLL, POOL_TAG('A', 'R', 'F', 'T'))`.\n- Scalar `BOOLEAN` arguments can render as `TRUE` or `FALSE`.\n\n## Kernel Pattern Driver Sample\n\n`samples\u002Fkernel_pattern_driver` contains a WDM driver corpus for PseudoForge analysis regression testing. It follows the shape of the Microsoft `Windows-driver-samples` WDM IOCTL sample while concentrating common kernel driver call combinations into one binary.\n\nIncluded patterns:\n\n- `DriverEntry`, `DriverUnload`, `IRP_MJ_CREATE`, `IRP_MJ_CLOSE`, and `IRP_MJ_DEVICE_CONTROL`\n- `IoCreateDevice`, `IoCreateSymbolicLink`, and `METHOD_BUFFERED` IOCTL validation\n- `ExAllocatePool2`, `ExFreePoolWithTag`, and `NPAGED_LOOKASIDE_LIST`\n- `LIST_ENTRY` event retention and variable output with `FIELD_OFFSET`\n- `FAST_MUTEX`, `ERESOURCE`, and critical-region pairing\n- `PsLookupProcessByProcessId` and `ObDereferenceObject`\n- `KTIMER`, `KDPC`, and `IoQueueWorkItem`\n- Optional process, image, and thread callback registration\n- Optional `ObRegisterCallbacks` process object callback registration\n- LIST_ENTRY-backed process whitelist\u002Fblacklist traversal with `CONTAINING_RECORD`\n- A single-function object pre-operation callback path in `PfkpObjectPreOperation`, including requested-access checks and requester whitelist auto-add behavior\n\nBuild:\n\n```powershell\n.\\samples\\kernel_pattern_driver\\tools\\build.ps1 -Configuration Release\n```\n\nOutput:\n\n```text\nsamples\\kernel_pattern_driver\\x64\\Release\\PfKernelPattern.sys\nsamples\\kernel_pattern_driver\\x64\\Release\\PfKernelPatternTool.exe\n```\n\n## WDK Kernel API Profile\n\nPseudoForge reads `ida_pseudoforge\u002Fprofiles\u002Fkernel_api.json` by default for WDK API prototypes and selected argument semantics. Runtime lookup paths can also use split family files when they are present, such as `kernel_functions.json`, `kernel_enums.json`, `kernel_indices.json`, and `kernel_symbol_index.json`, before falling back to the monolithic profile. `kernel_api_overrides.json` adds private wrapper aliases and deterministic argument semantics that do not exist directly in WDK headers.\n\nRegenerate the profile from WDK headers:\n\n```powershell\npython -B .\\tools\\build_kernel_api_profile.py --list-versions\npython -B .\\tools\\build_kernel_api_profile.py --version 10.0.26100.0\npython -B .\\tools\\build_kernel_api_profile.py --version 10.0.26100.0 --split-output-dir .\\ida_pseudoforge\\profiles\n```\n\nInspect selected functions without writing a profile:\n\n```powershell\npython -B .\\tools\\build_kernel_api_profile.py --version 10.0.26100.0 --header wdm.h --dry-run --function ExAllocatePool2 --function ExFreePoolWithTag\n```\n\nOptions:\n\n- `--wdk-include-root`: defaults to `C:\\Program Files (x86)\\Windows Kits\\10\\Include`.\n- `--version`: WDK include version; omitted means the newest installed `km` include directory.\n- `--header`: header name to parse; may be repeated.\n- `--directory`: WDK include subdirectory; defaults to `km` and `shared`.\n- `--all-km-headers`: parse only `km\\*.h` for the selected WDK version.\n- `--out`: output profile path; defaults to `ida_pseudoforge\u002Fprofiles\u002Fkernel_api.json`.\n- `--split-output-dir`: also write split family profiles such as `kernel_functions.json`, `kernel_enums.json`, `kernel_indices.json`, and `kernel_symbol_index.json`.\n- `--split-only`: with `--split-output-dir`, skip writing the monolithic `--out` profile.\n- `--function`: function name to extract; may be repeated.\n- `--known-only`: generate only functions with PseudoForge semantic overlays.\n- `--summary`: print function\u002Fenum count summary.\n- `--verbose-summary`: include function names in the summary.\n- `--dry-run`: print JSON to stdout instead of writing a file.\n\n`profiles_manifest.json` records source version, profile kind, entry counts,\nand SHA-256 metadata for the built-in profile files. Export summaries include\nthe active profile root, loaded profile names, and manifest entries for profiles\ntouched during a run.\n\nSmoke-check the split-profile load path without forcing a brittle timing gate:\n\n```powershell\npython -B .\\tools\\profile_load_smoke.py --family functions --repeat 100 --json\n```\n\nThe smoke command measures cold-load and repeated cached lookup time. It fails\nif profile warnings are emitted, no entries load, or a split family file exists\nbut `kernel_api.json` is loaded instead. Optional `--max-cold-ms` and\n`--max-repeated-ms` thresholds can be used for local performance tracking.\n\nAlternate target-build profile sets can be selected with\n`PSEUDOFORGE_PROFILE_DIR`, the `--profile-dir` option on Python tools, or\n`-ProfileDir` on `tools\u002Frun_pseudoforge_ida_batch.ps1`. Inside IDA, use\n`Edit\u002FPseudoForge\u002FConfigure profile directory` to persist an interactive\nprofile root selection. The default remains the built-in profile directory.\n\nThe built-in profile is currently generated from WDK `10.0.26100.0` and includes:\n\n- 470 headers\n- 3501 function prototypes\n- 1760 enums\n- 8354 structures\n- 19865 typedef aliases\n- 58251 macros\n- 93592 symbol index entries\n- Semantic overlays for `POOL_FLAGS`, `BOOLEAN`, pool tag parameters, and selected resource\u002Flist\u002Fpool APIs\n- Override aliases such as `Obp -> Ob`, `Psp -> Ps`, `Iop -> Io`, `Mmp -> Mm`, and `Sep -> Se`\n- Derived argument semantics for exact `Tag` arguments in pool and `WithTag` APIs\n\nThe profile includes a `symbols` index for name-based lookup. Names such as `NdisRegisterProtocolDriver`, `FltRegisterFilter`, `PDEVICE_OBJECT`, and `POOL_FLAG_PAGED` can be found as functions, aliases, macros, or enum members. Private wrapper aliases are exposed as `function_alias` entries, so a call such as `ObpReferenceObjectByHandleWithTag` can use the public `ObReferenceObjectByHandleWithTag` prototype metadata while preserving the original call spelling.\n\n## `.forge` Analysis Files\n\nPseudoForge stores analyzed cleaned pseudocode beside the target binary.\n\nExample:\n\n```text\nC:\\work\\a.exe\nC:\\work\\a.forge\n```\n\nRules:\n\n- The filename keeps the input stem and changes only the extension to `.forge`.\n- If IDA cannot provide the input file path, the IDB path is used as a fallback.\n- One `.forge` file can contain multiple functions.\n- Each function section is wrapped with `\u002F\u002F PSEUDOFORGE FUNCTION BEGIN ea=...` and `END` markers.\n- Re-analyzing the same EA replaces only that function section.\n- Other function sections are preserved.\n- `Show current analysis result` shows only the matching function section.\n- `Analyzed functions...` lists all cached `.forge` sections without opening the full aggregate file first.\n- The preview context-menu action `PseudoForge\u002FAnalyzed functions...` provides the same chooser from inside a preview window.\n- Run `Analyze current function` to refresh the current function section.\n\n## LLM Configuration Inside IDA\n\nLLM rename assist can be configured without a separate CLI.\n\n1. Run `Edit\u002FPseudoForge\u002FConfigure LLM rename assist`.\n2. Choose `Yes` for `Enable PseudoForge LLM rename assist?`.\n3. Select a provider in the read-only provider combo box.\n4. Enter the base URL for HTTP providers.\n5. Enter an API key only if the selected HTTP provider has no stored key.\n6. Select a model in the provider-specific read-only model combo box.\n7. Enter a command template for CLI providers.\n8. Set the timeout in seconds.\n9. Subsequent `Analyze current function`, `Export cleaned pseudocode`, and `Apply selected renames` actions use LLM rename assist when it is enabled.\n\nAPI key policy:\n\n- `openai_compatible`, `openrouter`, and `deepseek_api` require API keys.\n- API keys are stored under provider-specific `credentials`, not under `llm`.\n- Existing provider keys are reused when changing models.\n- To replace a key, edit or delete the provider credential in `pseudoforge_config.json`, then run the configuration action again.\n\nSupported provider IDs:\n\n```text\nopenai_compatible\nopenrouter\nchatgpt_oauth_via_codex_cli\ncodex_cli\nclaude_login_via_claude_cli\nclaude_cli\ndeepseek_api\n```\n\nDefault provider settings:\n\n| Provider | Default model | Default endpoint or command |\n| --- | --- | --- |\n| `openai_compatible` | `gpt-5-mini` | `https:\u002F\u002Fapi.openai.com\u002Fv1` |\n| `openrouter` | `openrouter\u002Fauto` | `https:\u002F\u002Fopenrouter.ai\u002Fapi\u002Fv1` |\n| `chatgpt_oauth_via_codex_cli` | `gpt-5-mini` | `codex exec -m {model} --skip-git-repo-check --sandbox read-only --output-last-message {output_file} -` |\n| `codex_cli` | `gpt-5-mini` | `codex exec -m {model} --skip-git-repo-check --sandbox read-only --output-last-message {output_file} -` |\n| `claude_login_via_claude_cli` | `claude-sonnet-4-6` | `claude -p --model {model} --permission-mode dontAsk --output-format text --no-session-persistence --tools \"\" --setting-sources project,local` |\n| `claude_cli` | `claude-sonnet-4-6` | `claude -p --model {model} --permission-mode dontAsk --output-format text --no-session-persistence --tools \"\" --setting-sources project,local` |\n| `deepseek_api` | `deepseek-v4-flash` | `https:\u002F\u002Fapi.deepseek.com` |\n\nThe default timeout is 60 seconds.\n\nModel discovery:\n\n- IDA configuration uses a non-blocking model discovery cache. If no live model\n  catalog is cached yet, the dialog opens with provider static models while a\n  background refresh updates the cache for the next configuration run.\n- `chatgpt_oauth_via_codex_cli` and `codex_cli` read the Codex model catalog through `codex debug models` using argv-based subprocess execution, not a shell command string.\n- If `codex debug models` fails, `%USERPROFILE%\\.codex\\models_cache.json` is used.\n- Claude CLI providers use provider-specific static model lists. This is the expected path because Claude CLI does not expose a model catalog command. The static list starts with the current Claude API\u002FClaude Code model IDs and aliases: `claude-opus-4-8`, `claude-sonnet-4-6`, and `claude-haiku-4-5`.\n- HTTP providers query the selected base URL's `\u002Fmodels` endpoint.\n- If an enabled HTTP provider has no stored key, the key prompt appears before model discovery.\n- Discovery failures fall back to provider-specific static model lists.\n- A custom model stored in `pseudoforge_config.json` is temporarily added to the combo box on the next configuration run so the current setting is not lost.\n\n`chatgpt_oauth_via_codex_cli` lets IDA call Codex CLI with the ChatGPT OAuth session saved by `codex login`. `claude_login_via_claude_cli` lets IDA call Claude CLI with the Anthropic account session saved by `claude auth login`. PseudoForge does not implement in-IDA browser login. `codex_cli` and `claude_cli` remain generic local CLI bridges with editable command templates.\n\nCLI command template placeholders:\n\n```text\n{prompt_file}   temporary file containing the prompt\n{output_file}   temporary file expected to contain the provider response\n{model}         selected model name\n```\n\nPseudoForge also sends the prompt to CLI providers over stdin. If `{output_file}` is present, the file is preferred; otherwise stdout is used. CLI command templates are parsed into argv and executed with `shell=False` by default. On Windows, CLI provider calls and Codex model discovery request hidden child console windows so local CLI bridges such as Claude CLI do not flash a separate console during normal runs. Prefix a template with `shell:` or `raw-shell:` only when an explicitly reviewed advanced shell pipeline is required. The default Codex, ChatGPT, and Claude templates include `{model}`. Claude defaults also include `--setting-sources project,local` so user\u002Fglobal Claude hooks do not pollute the JSON-only rename-assist response. Old default templates that omitted `{model}`, used unsupported Codex CLI flags, or used older Claude CLI defaults without the selected model or setting-source isolation are migrated on load; user-created custom templates are preserved.\n\nConfig path:\n\n```text\n\u003CIDA user directory>\\pseudoforge_config.json\n```\n\nExample:\n\n```json\n{\n  \"llm\": {\n    \"enabled\": true,\n    \"provider\": \"openai_compatible\",\n    \"base_url\": \"https:\u002F\u002Fapi.openai.com\u002Fv1\",\n    \"model\": \"gpt-5-mini\",\n    \"timeout_seconds\": 60,\n    \"command_template\": \"\",\n    \"extra_headers\": {}\n  },\n  \"profile_dir\": \"\",\n  \"preview\": {\n    \"backend\": \"simple\"\n  },\n  \"credentials\": {\n    \"openai_compatible\": {\n      \"api_key\": \"sk-...\"\n    }\n  }\n}\n```\n\nOpenRouter example:\n\n```json\n{\n  \"llm\": {\n    \"enabled\": true,\n    \"provider\": \"openrouter\",\n    \"base_url\": \"https:\u002F\u002Fopenrouter.ai\u002Fapi\u002Fv1\",\n    \"model\": \"openrouter\u002Fauto\",\n    \"timeout_seconds\": 60,\n    \"command_template\": \"\",\n    \"extra_headers\": {\n      \"X-Title\": \"PseudoForge\"\n    }\n  },\n  \"credentials\": {\n    \"openrouter\": {\n      \"api_key\": \"sk-or-...\"\n    }\n  }\n}\n```\n\nDeepSeek API example:\n\n```json\n{\n  \"llm\": {\n    \"enabled\": true,\n    \"provider\": \"deepseek_api\",\n    \"base_url\": \"https:\u002F\u002Fapi.deepseek.com\",\n    \"model\": \"deepseek-v4-flash\",\n    \"timeout_seconds\": 60,\n    \"command_template\": \"\",\n    \"extra_headers\": {}\n  },\n  \"credentials\": {\n    \"deepseek_api\": {\n      \"api_key\": \"\u003Cdeepseek-api-key>\"\n    }\n  }\n}\n```\n\nCodex CLI \u002F ChatGPT OAuth via Codex CLI example:\n\n```json\n{\n  \"llm\": {\n    \"enabled\": true,\n    \"provider\": \"chatgpt_oauth_via_codex_cli\",\n    \"base_url\": \"\",\n    \"model\": \"gpt-5-mini\",\n    \"timeout_seconds\": 120,\n    \"command_template\": \"codex exec -m {model} --skip-git-repo-check --sandbox read-only --output-last-message {output_file} -\",\n    \"extra_headers\": {}\n  },\n  \"credentials\": {}\n}\n```\n\nClaude CLI login example:\n\n```json\n{\n  \"llm\": {\n    \"enabled\": true,\n    \"provider\": \"claude_login_via_claude_cli\",\n    \"base_url\": \"\",\n    \"model\": \"claude-sonnet-4-6\",\n    \"timeout_seconds\": 120,\n    \"command_template\": \"claude -p --model {model} --permission-mode dontAsk --output-format text --no-session-persistence --tools \\\"\\\"\",\n    \"extra_headers\": {}\n  },\n  \"credentials\": {}\n}\n```\n\nIf an LLM call fails, PseudoForge falls back to the deterministic plan and records the failure in warnings. The IDB write boundary is unchanged: only user-selected, validator-gated renames can be applied.\n\n## Export Output\n\nExport is the durable artifact path for PseudoForge analysis. It is not an apply path and is not meant to rewrite the IDB. The export bundle lets reviewers compare the cleaned output against the original decompiler text, inspect why a rename or semantic cleanup appeared, archive analysis results, and build regression samples from real functions.\n\n`Export cleaned pseudocode` writes:\n\n```text\n\u003Cfunction>.cleaned.cpp\n\u003Cfunction>.switch-outline.cpp\n\u003Cfunction>.rename-map.json\n\u003Cfunction>.flow-report.md\n\u003Cfunction>.rule-report.json\n\u003Cfunction>.raw.cpp\n\u003Cfunction>.warnings.json\n\u003Cfunction>.raw-vs-cleaned.diff\n\u003Cfunction>.summary.json\n```\n\nThe IDA Free CLI keeps its compatibility summary filename as\n`\u003Cfunction>.ida-free-summary.json`.\n\nFile purposes:\n\n- `.cleaned.cpp`: readable pseudocode with validated renames and NTSTATUS literal cleanup.\n- `.switch-outline.cpp`: recovered dispatcher case values and conservative body excerpts.\n- `.rename-map.json`: full `CleanPlan` JSON.\n- `.flow-report.md`: dispatcher, recovered cases, cleanup labels, and warning report.\n- `.rule-report.json`: deterministic rule matches, rejected emissions, load errors, and validation errors.\n- `.raw.cpp`: original captured decompiler text used as analysis input.\n- `.warnings.json`: plan and profile-load warnings as reviewable JSON.\n- `.raw-vs-cleaned.diff`: unified diff from raw pseudocode to cleaned output.\n- `.summary.json` \u002F `.ida-free-summary.json`: per-function export metadata, counts, deterministic rule diagnostics, rule load\u002Fvalidation error details, active profile root, loaded profile names, active profile manifests, profile warnings, and artifact paths.\n\nArtifact parity:\n\n| Artifact | IDA interactive export | Offline CLI | IDA Free CLI |\n| --- | --- | --- | --- |\n| Cleaned pseudocode | yes | yes | yes |\n| Switch outline | yes | yes | yes |\n| Rename map \u002F CleanPlan | yes | yes | yes |\n| Flow report | yes | yes | yes |\n| Rule report | yes | yes | yes |\n| Raw pseudocode | yes | yes | yes |\n| Warnings JSON | yes | yes | yes |\n| Raw-vs-cleaned diff | yes | yes | yes |\n| Per-function summary | yes | yes | yes |\n| Run manifest | no | no | yes |\n\nCaveats:\n\n- `switch-outline.cpp` does not synthesize deep shared branches or fallthrough bodies.\n- Control-flow rewrites are preview\u002Fexport-only artifacts and never modify the IDB.\n- The IDB receives only user-selected local or argument renames.\n- Export artifacts are intended to be reviewed against the original pseudocode.\n\n## Offline CLI\n\nRun the core engine outside IDA:\n\n```powershell\npython -B .\\tools\\pseudoforge_cli.py .\\samples\\pseudocode\\NtSetSystemInformation_switch_renamed.cpp --out $env:TEMP\\pseudoforge_cli_smoke\n```\n\nExpected output:\n\n```text\nPseudoForge export complete\nFunction: NtSetSystemInformation\nRenames: \u003Ccount>\nFlow rewrites: \u003Ccount>\ncleaned_pseudocode: ...\nswitch_outline: ...\nrename_map: ...\nflow_report: ...\nrule_report: ...\nraw_pseudocode: ...\nwarnings: ...\nraw_vs_cleaned_diff: ...\nsummary: ...\n```\n\nUse LLM rename assist with provider-specific environment variables or options:\n\n```powershell\n$env:PSEUDOFORGE_OPENAI_API_KEY = \"\u003Capi-key>\"\n$env:PSEUDOFORGE_OPENAI_MODEL = \"gpt-5-mini\"\npython -B .\\tools\\pseudoforge_cli.py .\\samples\\pseudocode\\NtSetSystemInformation_switch_renamed.cpp --llm-renames --out $env:TEMP\\pseudoforge_cli_smoke\n```\n\nOpenRouter:\n\n```powershell\n$env:PSEUDOFORGE_OPENROUTER_API_KEY = \"\u003Copenrouter-api-key>\"\npython -B .\\tools\\pseudoforge_cli.py .\\samples\\pseudocode\\NtSetSystemInformation_switch_renamed.cpp --llm-renames --llm-provider openrouter --out $env:TEMP\\pseudoforge_cli_smoke\n```\n\nDeepSeek:\n\n```powershell\n$env:PSEUDOFORGE_DEEPSEEK_API_KEY = \"\u003Cdeepseek-api-key>\"\npython -B .\\tools\\pseudoforge_cli.py .\\samples\\pseudocode\\NtSetSystemInformation_switch_renamed.cpp --llm-renames --llm-provider deepseek_api --out $env:TEMP\\pseudoforge_cli_smoke\n```\n\nCodex CLI:\n\n```powershell\ncodex login\npython -B .\\tools\\pseudoforge_cli.py .\\samples\\pseudocode\\NtSetSystemInformation_switch_renamed.cpp --llm-renames --llm-provider codex_cli --llm-timeout 120 --out $env:TEMP\\pseudoforge_cli_smoke\n```\n\nClaude CLI login:\n\n```powershell\nclaude auth login\npython -B .\\tools\\pseudoforge_cli.py .\\samples\\pseudocode\\NtSetSystemInformation_switch_renamed.cpp --llm-renames --llm-provider claude_login_via_claude_cli --llm-timeout 120 --out $env:TEMP\\pseudoforge_cli_smoke\n```\n\nOptional environment variables:\n\n```text\nPSEUDOFORGE_OPENAI_API_KEY\nPSEUDOFORGE_OPENAI_BASE_URL\nPSEUDOFORGE_OPENAI_MODEL\nPSEUDOFORGE_OPENROUTER_API_KEY\nPSEUDOFORGE_OPENROUTER_BASE_URL\nPSEUDOFORGE_OPENROUTER_MODEL\nPSEUDOFORGE_DEEPSEEK_API_KEY\nPSEUDOFORGE_DEEPSEEK_BASE_URL\nPSEUDOFORGE_DEEPSEEK_MODEL\n```\n\nDefault values:\n\n```text\nPSEUDOFORGE_OPENAI_BASE_URL=https:\u002F\u002Fapi.openai.com\u002Fv1\nPSEUDOFORGE_OPENAI_MODEL=gpt-5-mini\nPSEUDOFORGE_OPENROUTER_BASE_URL=https:\u002F\u002Fopenrouter.ai\u002Fapi\u002Fv1\nPSEUDOFORGE_OPENROUTER_MODEL=openrouter\u002Fauto\nPSEUDOFORGE_DEEPSEEK_BASE_URL=https:\u002F\u002Fapi.deepseek.com\nPSEUDOFORGE_DEEPSEEK_MODEL=deepseek-v4-flash\n```\n\nLLM rename assist only adds candidate names to the deterministic rename plan. LLM output must still pass JSON parsing, confidence thresholding, and rename validation.\n\n## IDA Free Offline CLI\n\nIDA Free is not a supported interactive plugin target for PseudoForge. The interactive actions require IDAPython and local Hex-Rays pseudocode APIs, which are not available in IDA Free. Users can still copy or save a single cloud-decompiled pseudocode function and process that text outside IDA:\n\n```powershell\npython -B .\\tools\\pseudoforge_free_cli.py .\\samples\\pseudocode\\NtSetSystemInformation_switch_renamed.cpp --out $env:TEMP\\pseudoforge_free_cli_smoke\n```\n\nThe IDA Free CLI accepts one or more text files. Each file should contain one complete function. Leading or trailing copied text is tolerated when the function boundary is unambiguous. Multiple functions in one file fail closed with an actionable error.\n\nProject-local deterministic rules:\n\n```powershell\npython -B .\\tools\\pseudoforge_free_cli.py .\\copied_from_ida_free.cpp --project-root . --rules .\\extra_rules --out $env:TEMP\\pseudoforge_free_cli_smoke\n```\n\nOptional offline LLM rename assist:\n\n```powershell\npython -B .\\tools\\pseudoforge_free_cli.py .\\copied_from_ida_free.cpp --llm --llm-provider claude_login_via_claude_cli --llm-timeout 120 --out $env:TEMP\\pseudoforge_free_cli_llm\n```\n\nProject-local rules and LLM rename assist together:\n\n```powershell\nNew-Item -ItemType Directory -Force .\\pseudoforge_rules | Out-Null\nclaude auth login\npython -B .\\tools\\pseudoforge_free_cli.py .\\copied_from_ida_free.cpp `\n  --project-root . `\n  --rules .\\extra_rules `\n  --llm `\n  --llm-provider claude_login_via_claude_cli `\n  --llm-timeout 120 `\n  --out $env:TEMP\\pseudoforge_free_rules_llm\n```\n\nIn this mode, builtin rules, `.\\pseudoforge_rules\\*.json`, user-global rules, and `--rules` directories are loaded first. LLM rename suggestions are then added as optional candidates and still pass deterministic validation before they can appear in the output plan. Invalid rule packs are reported in the rule report and do not crash analysis. LLM provider failures fall back to the deterministic plan.\n\nThe default text console output prints incremental progress before long phases such as LLM-assisted plan building and artifact writing. Use `--no-progress` when only the final text summary is needed.\n\nExample IDA Free CLI run with project-local rules and Claude CLI login:\n\n![PseudoForge IDA Free CLI command and output artifacts](screenshots\u002Fida_free_usage.png)\n\nThe screenshot shows the current text console flow with incremental progress and a structured final status summary.\n\nExample IDA Free result comparison. The left side is IDA Free cloud-decompiled pseudocode, and the right side is the cleaned PseudoForge offline output:\n\n![IDA Free raw pseudocode beside PseudoForge cleaned output](screenshots\u002Fida_free_result.png)\n\nStructured console output:\n\n```powershell\npython -B .\\tools\\pseudoforge_free_cli.py .\\copied_from_ida_free.cpp --format json --out $env:TEMP\\pseudoforge_free_cli_json\n```\n\nWith `--format json`, stdout remains machine-readable JSON. Progress messages are written to stderr so scripts can continue parsing stdout safely.\n\nIDA Free CLI artifacts include:\n\n- `\u003Cfunction>.cleaned.cpp`\n- `\u003Cfunction>.switch-outline.cpp`\n- `\u003Cfunction>.rename-map.json`\n- `\u003Cfunction>.flow-report.md`\n- `\u003Cfunction>.rule-report.json`\n- `\u003Cfunction>.raw.cpp`\n- `\u003Cfunction>.warnings.json`\n- `\u003Cfunction>.raw-vs-cleaned.diff`\n- `\u003Cfunction>.ida-free-summary.json`\n- `pseudoforge-free-report.json`\n\nIDA Free CLI limitations:\n\n- No interactive PseudoForge menu, preview action, or apply-renames action.\n- No IDB writes.\n- No direct IDAPython, IDA SDK, or local Hex-Rays API access.\n- Output quality depends on the copied decompiler text quality.\n- Inferred structure rewrites and semantic comments still require review against the original pseudocode.\n\n## Headless IDA Batch\n\n`tools\u002Fpseudoforge_ida_batch.py` runs inside IDA batch mode. It opens a `.i64` or `.idb`, calls `ida_hexrays.decompile()` per function, analyzes through PseudoForge, appends `.forge` sections, and writes JSONL progress reports. The normal entrypoint is the PowerShell wrapper `tools\u002Frun_pseudoforge_ida_batch.ps1`.\n\nExample:\n\n```powershell\n.\\tools\\run_pseudoforge_ida_batch.ps1 `\n  -IdaPath \"C:\\Path\\To\\IDA\\ida.exe\" `\n  -IdbPath \"D:\\Path\\To\\ntoskrnl.exe.i64\" `\n  -TargetPath \"D:\\Path\\To\\ntoskrnl.exe\" `\n  -OutputDir \"$env:TEMP\\pseudoforge_ida_batch\\ntoskrnl\" `\n  -OverwriteForge\n```\n\nSingle-function smoke:\n\n```powershell\n.\\tools\\run_pseudoforge_ida_batch.ps1 `\n  -IdaPath \"C:\\Path\\To\\IDA\\ida.exe\" `\n  -IdbPath \"D:\\Path\\To\\ntoskrnl.exe.i64\" `\n  -TargetPath \"D:\\Path\\To\\ntoskrnl.exe\" `\n  -NameRegex \"^NtSetSystemInformation$\" `\n  -MaxFunctions 1\n```\n\nWrapper options:\n\n- `-MaxFunctions N`: analyze only the first N matching functions.\n- `-NameRegex REGEX`: filter functions by name.\n- `-Resume`: skip EAs already present in the existing `.forge`.\n- `-OverwriteForge`: create a fresh `.forge` before append-only batch export.\n- `-UpsertForge`: slower path that verifies aggregate section replacement.\n- `-CancelFile PATH`: stop before the next function when the sentinel file exists.\n- `-LlmRenames`: use saved or explicit LLM rename assist settings.\n- `-NoPdb`: pass `-Opdb:off` to IDA so validation runs do not load PDB\u002Fdebug symbols.\n- `-NoWait`: start the IDA process and return immediately.\n\nSummarize an existing report:\n\n```powershell\npython -B .\\tools\\summarize_pseudoforge_ida_batch.py \"$env:TEMP\\pseudoforge_ida_batch\\ntoskrnl\\ntoskrnl.exe_\u003Ctimestamp>.jsonl\"\n```\n\nCompare raw Hex-Rays output against PseudoForge output:\n\n```powershell\n.\\tools\\run_pseudoforge_ida_batch.ps1 `\n  -IdaPath \"C:\\Path\\To\\IDA\\ida.exe\" `\n  -IdbPath \"D:\\Path\\To\\ntoskrnl.exe.i64\" `\n  -TargetPath \"D:\\Path\\To\\ntoskrnl.exe\" `\n  -NameRegex \"^NtSetSystemInformation$\" `\n  -MaxFunctions 1 `\n  -CompareDir \"$env:TEMP\\pseudoforge_ida_batch\\ntoskrnl_compare\"\n```\n\n`-CompareDir` writes:\n\n- `raw\\*.cpp`: raw IDA Hex-Rays `cfunc.get_pseudocode()` text.\n- `cleaned\\*.cpp`: PseudoForge normalized\u002Fexport pseudocode.\n- `forge\\*.forge`: full `.forge` section for the function.\n- `diff\\*.diff`: raw vs cleaned unified diff.\n\nEach JSONL function record includes legacy comparison paths, a shared-style\n`artifacts` map, SHA-256 hashes, line counts, and diff line counts.\nBatch reports also include `progress` records before each function starts so a\nlong decompile or LLM-assisted function can be identified before it finishes.\nWhen `-CancelFile` is used, creating that file requests a cooperative stop at\nthe next function boundary and records a `stop` event with `reason=cancel_file`.\nIDA batch rendering also applies direct helper alias postprocessing so\nstrongly evidenced direct `sub_*` helper callees can render as standard memory\nhelpers in compare artifacts without requiring a prior interactive all-function\nanalysis pass.\n\nScore a compare directory:\n\n```powershell\npython -B .\\tools\\score_pseudoforge_quality.py `\n  --compare-dir \"$env:TEMP\\pseudoforge_ida_batch\\ntoskrnl_compare\" `\n  --report \"$env:TEMP\\pseudoforge_ida_batch\\ntoskrnl\\ntoskrnl.exe_\u003Ctimestamp>.jsonl\" `\n  --json-output \"$env:TEMP\\pseudoforge_ida_batch\\quality.json\" `\n  --markdown-output \"$env:TEMP\\pseudoforge_ida_batch\\quality.md\"\n```\n\nThe quality scorer is heuristic and corpus-agnostic. It is intended for\nregression comparison across no-PDB runs, not as a correctness proof.\n\nTo include the same LLM assist path used by interactive IDA Analyze, add `-LlmRenames`. Full-kernel LLM batch runs can issue many provider calls, so check cost and runtime first.\n\nLLM wrapper overrides:\n\n- `-LlmProvider openrouter|chatgpt_oauth_via_codex_cli|codex_cli|claude_login_via_claude_cli|claude_cli|deepseek_api|openai_compatible`\n- `-LlmModel MODEL`\n- `-LlmTimeout SECONDS`\n- `-LlmBaseUrl URL`\n- `-LlmCommand COMMAND_TEMPLATE`\n- `-LlmApiKey KEY`\n\nNo-op CLI provider smoke:\n\n```powershell\n$noopProvider = \"python \" + (Resolve-Path .\\tools\\empty_llm_rename_provider.py).Path\n.\\tools\\run_pseudoforge_ida_batch.ps1 `\n  -IdaPath \"C:\\Path\\To\\IDA\\ida.exe\" `\n  -IdbPath \"D:\\Path\\To\\ntoskrnl.exe.i64\" `\n  -NameRegex \"^NtSetSystemInformation$\" `\n  -MaxFunctions 1 `\n  -LlmRenames `\n  -LlmProvider codex_cli `\n  -LlmCommand $noopProvider\n```\n\nFunctions that Hex-Rays cannot decompile are recorded as `skipped`, not as PseudoForge failures.\n\nFor unknown third-party binary validation, use `-NoPdb` and review the IDA log for unexpected symbol loading. The wrapper also retries once when a fresh IDA load exits with an empty report file before the batch script has produced records.\n\n## Deterministic Rules\n\nPseudoForge includes a v1 deterministic rules matching engine. The supported production scope is data-only JSON rules for `rename` and `semantic_comment`.\n\nRule load paths:\n\n```text\nida_pseudoforge\u002Frules\u002Fbuiltin\u002F*.json\n.\\pseudoforge_rules\\*.json\n%APPDATA%\\PseudoForge\\rules\\*.json\n```\n\nInteractive IDA analysis resolves `.\\pseudoforge_rules` relative to the analyzed input binary directory. Offline CLI resolves it relative to the source pseudocode file and also accepts explicit `--rules-dir`.\n\nBuiltin rules currently mirror low-risk deterministic hard-coded passes for report\u002Fparity visibility. They do not replace existing hard-coded rename validation, cleanup classification, flow recovery, or kernel API rewrite behavior.\n\nAuthoring workflow:\n\n1. Create `pseudoforge_rules` beside the analyzed `.idb`, binary, or pseudocode input.\n2. Add a rule pack JSON file, for example `project_kernel_rules.json`.\n3. Validate the pack before use.\n4. In IDA, run PseudoForge analysis normally. In the CLI, place rules beside the source input or pass `--rules-dir .\\pseudoforge_rules`.\n5. Use `--rule-report` to inspect matched rules, rejected emissions, load errors, and validation errors.\n\nValidation:\n\n```powershell\nNew-Item -ItemType Directory -Force .\\pseudoforge_rules\npython -B .\\tools\\validate_pseudoforge_rules.py .\\ida_pseudoforge\\rules\\builtin\npython -B .\\tools\\validate_pseudoforge_rules.py .\\pseudoforge_rules\n```\n\nProject-local rule pack example:\n\n```json\n{\n  \"schema_version\": 1,\n  \"id\": \"project.kernel_object_rules\",\n  \"description\": \"Project-local PseudoForge deterministic rules for kernel object callback analysis.\",\n  \"rules\": [\n    {\n      \"id\": \"project.rename.exact_previous_mode\",\n      \"phase\": \"rename\",\n      \"priority\": 100,\n      \"confidence\": 0.99,\n      \"scope\": {\n        \"lvars_any\": [\"PreviousMode\"]\n      },\n      \"match\": {\n        \"text_contains\": \"PreviousMode\"\n      },\n      \"emit\": {\n        \"kind\": \"rename\",\n        \"rename_kind\": \"lvar\",\n        \"target\": \"PreviousMode\",\n        \"new_name\": \"previousMode\",\n        \"evidence\": \"Hex-Rays kept kernel PreviousMode casing\"\n      }\n    },\n    {\n      \"id\": \"project.rename.requester_process\",\n      \"phase\": \"rename\",\n      \"priority\": 100,\n      \"confidence\": 0.94,\n      \"scope\": {\n        \"calls_any\": [\"PsGetCurrentProcessId\"]\n      },\n      \"match\": {\n        \"assignment_regex\": \"\\\\b(?P\u003Cdst>[A-Za-z_][A-Za-z0-9_]*)\\\\s*=\\\\s*PsGetCurrentProcessId\\\\(\\\\)\\\\b\"\n      },\n      \"emit\": {\n        \"kind\": \"rename\",\n        \"rename_kind\": \"lvar\",\n        \"target\": \"$dst\",\n        \"new_name\": \"requesterProcessId\",\n        \"evidence\": \"Local receives current process id in object callback path\"\n      }\n    },\n    {\n      \"id\": \"project.comment.object_pre_operation_callback\",\n      \"phase\": \"semantic_comment\",\n      \"priority\": 80,\n      \"confidence\": 0.90,\n      \"scope\": {\n        \"function_name_regex\": \".*ObjectPreOperation$\",\n        \"prototype_contains\": \"PRE_OPERATION\"\n      },\n      \"match\": {\n        \"text_contains_all\": [\"OB_OPERATION_HANDLE_CREATE\", \"OriginalDesiredAccess\"]\n      },\n      \"emit\": {\n        \"kind\": \"semantic_comment\",\n        \"comment_kind\": \"object_pre_operation\",\n        \"text\": \"Object pre-operation callback checks requested process access\",\n        \"evidence\": \"OB create operation and OriginalDesiredAccess are present\"\n      }\n    },\n    {\n      \"id\": \"project.override.updated_status_name\",\n      \"phase\": \"rename\",\n      \"priority\": 120,\n      \"confidence\": 0.96,\n      \"enabled\": true,\n      \"override_of\": \"builtin.local.updated_status\",\n      \"scope\": {\n        \"lvars_any\": [\"updated\"],\n        \"text_contains\": \"STATUS_\"\n      },\n      \"match\": {\n        \"text_contains\": \"updated\"\n      }","PseudoForge 是一个IDA Pro \u002F Hex-Rays插件，旨在将杂乱的伪代码转换为可审查且内核感知的清理工件。其核心功能包括通过确定性分析、可选的数据规则和LLM重命名建议构建验证过的`CleanPlan`，然后生成可以与原始伪代码对比的预览或导出文件。PseudoForge强调确定性优先，不依赖于LLM对任意代码进行重写，仅在用户选择并经过验证的情况下进行局部变量和参数重命名。该工具特别适用于需要对逆向工程中的内核代码进行清晰化处理的场景，如驱动程序分析、恶意软件研究等。","2026-06-11 04:09:05","CREATED_QUERY"]