Changelog0.6.0

Fixed

Fixed in fragcap 0.6.0.

The agent instruction files no longer assert things that stopped being true. The standing verification block in AGENTS.md had six items, four of which were stale, and it was phrased as a prohibition, so every agent session was directed to repeat them; most consequentially it still said live capture had never executed, which it did on 2026-08-20. The block now states its rule once and sorts its items into what has been discharged, with the evidence and the date, and what is still outstanding, with what would discharge it. AGENTS.md and CLAUDE.md also no longer claim a slice-numbered completion state that went stale roughly forty slices ago; both now name specs/ and changelog.d/ as the authority instead.

--help now wraps. Every one of the twenty-nine help pages previously emitted at least one line wider than 100 columns, the worst at 449, because clap was taken without its wrap_help feature and the wrapping function was compiled out entirely; 82 over-long lines across the surface become none, continuation text aligns under the description column, and a narrow terminal still shrinks. Help also no longer prints internal development vocabulary: slice identifiers, specification section numbers, appendix letters, build-feature names, and bare tier numbers are gone from all fifteen pages that carried them, and where the provenance is useful to a maintainer it moved to a comment clap does not publish. Two help lines that described behavior the tool does not have are corrected: capture --launch no longer reads as an instruction to pass a Steam app id to --target, where a bare integer is always a listing row number, and targets list now names the four columns it actually prints and says that it registers newly discovered titles rather than only reading. A selector that matches no row and looks like a number now says so: it names the interpretation it used, how many rows the listing holds, and how to register a Steam app id instead of guessing at it.

A capture now contains the target's traffic. It did not before: the first real end-to-end run produced a file that was 91 percent other processes' traffic, because nothing in the write path made the scope decision that specification section 12.3 places in userspace, and the narrowed kernel filter cannot engage until the target opens its first socket, which on a launcher-mediated title is tens of seconds after capture begins. Output is scoped to the target by default, and --scope all restores the previous behavior for correlating a target against the rest of a machine. Everything excluded is counted and reported, in two terms rather than one, so a packet dropped because it belonged to something else is distinguishable from a packet dropped because attribution had not yet named it. The completion summary also now reports what was written per process, which is the breakdown that would have made this defect visible on the first run rather than on a manual inspection of the file afterwards.

The run also narrates itself truthfully. It used to print filter narrowed to 0 endpoint(s) and then go silent, a line that means the opposite of how it reads (zero means no narrowing has happened and everything is still being captured), sampled at the one instant where zero is close to guaranteed, and never updated afterwards. It now says that capture is machine-wide while the target opens its first connection, and says again when capture becomes target-only, from the transition rather than from a sample. Machine-readable output receives an event per narrowing instead of a single reading of zero.

fragcap targets no longer reports "Steam DRM" for titles that carry no DRM. It did so on 28 of 32 rows, on the basis of steam_api64.dll, which is the Steamworks SDK redistributable and ships with essentially every Steam title whether or not any wrapper is applied. The label recorded an observation nobody made, and a signal that fires on nearly every row carries no information anyway. The two signature rows that produced it are gone, and the real discriminator is matched instead: the Steam DRM wrapper appends a PE section named .bind to the executable it wraps, so the binary-marker signature kind, which has been carried in the vocabulary and inert since it was introduced, is now matchable in a section: form that reads a bounded prefix of a candidate binary's own bytes. Verified on the operator's machine: Detroit Become Human, Palworld, and Enshrouded still report Steam DRM; ARC Raiders, Barotrauma, Shale Hill Secrets, and Trapped with Ivy and Piper no longer do.

Every command that scans now names what the scan did not cover, rather than counting it and leaving the operator to wonder. fragcap technologies on a directory with more executables than the scan cap used to print "no technologies detected" with nothing saying the scan had been truncated; targets add --exe recorded the row as incompletely scanned and printed nothing at all. Both say so now, as do the discovery paths.

The scan is bounded rather than a sweep of the tree. Only executables near the install root are candidates, capped at a count, each read as a bounded prefix. A candidate dropped by that cap is counted and named, and a candidate that could not be opened is recorded unreadable rather than treated as carrying no marker, so an incomplete scan is never presented as a clean one. The byte-sequence marker rows for Denuvo, Arxan, and VMProtect stay explicitly inert and counted, so the signature load still reconciles applied plus inert plus skipped to the rows loaded.

Two engines that were installed and invisible are now detected. Ren'Py is recognized from its package directory, its interpreter library, and its archive extension, and GameMaker from its runtime data file and its platform extension library. Ren'Py had been recognized by the launch-resolution rules for some time while remaining unnameable in the listing, which is the drift a new check now prevents: every engine those rules can select a client executable for must have a detection signature naming the same product, and adding one without the other fails the ordinary gate. On the operator's machine, trapped_with_ivy_piper now reports Ren'Py, shale_hill_secrets reports GameMaker, and ARC Raiders reports Unreal, which it did not before.

The one KNOWN column becomes two. It had been doing four jobs: it comma-joined engines with protection products so a reader could not tell which was which, and substituted a sentence about capture readiness when it had neither. ENGINE now names the detected engine and SENSITIVITIES names the anti-cheat and DRM products, partitioned on the category the findings already carried. The two readiness sentences are gone rather than moved, because each was a relabeling of a state the CAPTURE column already prints. The same partition and the same coverage state are carried by targets export, so the table and the machine-readable output cannot disagree, and targets show reports both lines too.

A blank technology column now says which kind of blank it is. A row that was scanned and matched nothing, a row whose scan could not finish, and a row nobody has scanned were previously indistinguishable, which asserted the first of the three for all of them. They render as -, incomplete, and not scanned. A target registered by an earlier build carries no coverage record and therefore reports not scanned until it is re-registered, which is correct: the tool does not claim a scan it did not run.

The Steam library walk no longer hands a soundtrack's install path to the rest of the pipeline as if it lived under steamapps/common/. A Music-typed title (the walk now reads Steam's own appinfo cache to tell) resolves under steamapps/music/ instead, which is where it actually is, and is excluded from discovery entirely: it has no network behavior and was previously appearing as a spurious, ready-labeled capture target with a warning about a directory that never existed.

fragcap targets now says when a registered target's install folder is gone, instead of rendering it identically to a healthy row. A title that was uninstalled but whose manifest lingered, a second library on a disconnected drive, or a scanned folder that moved, all render with a short note in the existing warning color (plain text when color is off), and the row is never offered as the listing's suggested next capture. Nothing is ever removed from the store because of this: the registration stays exactly as it was.

fragcap steam list now prints a header naming its columns, instead of two tab-separated fields a reader had to guess the meaning of. Each row is joined against the local store by its exact steam:<app_id> anchor (never by name, which two different installed titles can share) and shows one of three distinct states: registered and positioned in the most recent fragcap targets listing (its handle and row index), registered but not positioned (its handle only), or not registered at all. steam list only ever reads that listing snapshot; it never writes it, so running it does not change what fragcap capture <n> resolves to. Rows sort by title name, case-insensitive, tie-broken by app id, so the order is the same on repeated runs instead of the prior incidental app-id-as-string ordering. With no local store, or an unopenable one, the listing still succeeds and still names every installed title, with a warning that identity could not be joined.

fragcap targets now reports Easy Anti-Cheat for titles that ship it, which it did not before, even for titles measured shipping a visible EAC bootstrapper (EACLaunch.exe, AntiCheatInstaller.exe, an EasyAntiCheat/ or EasyAntiCheat_EOS/ directory). The in-tree signature set previously matched only the runtime's .dll/.sys files, none of which the two measured titles actually ship. EOSSDK-Win64-Shipping.dll alone continues to never report anti-cheat: it is the Epic Online Services SDK, shipped by many titles with no anti-cheat at all, and remains excluded by every new signature row and by a standing regression test.

A second evidence source now runs alongside the directory scan: Steam's own appinfo.vdf launch-entry metadata, which fragcap already parses, is classified for anti-cheat signals in its arguments and description fields (the enabling flags and launcher name a genuinely protected launch entry carries). The classifier matches only specific, unambiguous tokens, never a broad substring on words like "anti-cheat," so a launch variant that explicitly disables anti-cheat (measured on a Halo: MCC entry) correctly reports nothing. When both sources agree on a title, it is reported once, at the stronger evidence's fidelity.

capture --sink's help now names every scheme the parser actually accepts (file:, pcapng:, jsonl:, pipe:, fifo:, unix:, tcp://) and every ,key=value modifier (format, payload, rotate-size, rotate-duration, queue, timeout), where it previously named four schemes and none of the modifiers. --mode, --direction, --roles, and --wait now each state their effective default in --help, where none of the four did before. docs/fragcap-specification.md section 17.2 no longer documents -m, -q, or -V on capture, none of which the shipped grammar has ever had; the specification is corrected to match the shipped grammar rather than the reverse. steam list's help now names the route from a listed app id to a capturable target (targets add --steam <app_id>), which previously existed only in a source comment clap never rendered. capture's global --quiet/--silent/--json flags no longer sit inside the four target-input options (--target, --id, --process, and the positional selector); the four are now contiguous on every page, and the globals sort after every command's own options uniformly. capture --help and targets --help each now carry a worked example, drawn from the specification's own section 9.1 and README.md. Roughly two dozen further fields across the whole surface, never given a one-line -h summary at all, now have one, with their fuller explanation moved behind --help.

.gitignore no longer excludes files from anywhere in the repository whose path contains a segment named debug. The pattern arrived unanchored from a Cargo build-artifact template, and it had silently kept .agents/skills/debug/ out of every clone since the founding commit while that skill sat recorded in skills-lock.json the whole time; Cargo writes to target/debug, which the adjacent target pattern already covers. AGENTS.md and CLAUDE.md no longer state that the per-agent skill directories are populated with symlinks to the vendored set, which is generated by a tool this repository does not contain and was true of no checkout tested; both now say a checkout may carry none, and that nothing here depends on them. docs/plans/000-repository-foundation.md records that its skill count was wrong and that the selection rule it describes was an admission filter doing duty as a relevance test it cannot perform.