PROTOLENS(1)

πŸ“¦ version 0.3.4, in nixpkgs unstable

okay so welcome to protolens(1), bestie β€” it lives in section 1 of the General Commands Manual, aka the place where user commands hang out. This is the whole tour, no skips, no cuts. πŸ’…


✨ NAME ✨

protolens β€” a terminal viewer that decodes, navigates and extracts binary protobuf messages. literally the whole point 🫢


πŸ¦‹ SYNOPSIS πŸ¦‹

protolens [--descriptor-set] [-I|--proto-root] [-t|--type] [--raw]
[--indent] [--min-score] [-j|--jobs] [--theme]
[--override-preview-byte-budget] [--load-overrides] [--assume-binary]
[--eager-read] [--script] [--no-script] [--no-packing-penalty]
[--script-height] [-h|--help] [-V|--version] <BLOB> [subcommands]

🌸 DESCRIPTION 🌸

It's an interactive TUI. You point it at a binary protobuf, and it decodes it, lets you navigate around it, and pulls raw bytes out. That's the vibe check and it passes ✨

Want shell completion? Say less β€” here's how for each shell:

  • bash: source <(PROTOLENS_COMPLETE=bash protolens)
  • zsh: source <(PROTOLENS_COMPLETE=zsh protolens)
  • fish: PROTOLENS_COMPLETE=fish protolens | source

πŸ’– OPTIONS πŸ’–

  • --descriptor-set <DESCRIPTOR_SET> β€” the FileDescriptorSet used for root-type determination and type resolution. It can be a raw binary FileDescriptorSet or a #@ prototext-format FileDescriptorSet. It shares its env var with prototext/reproto (spec 0090), so one single PROTOTEXT_DESCRIPTOR_SET covers the whole toolset, no cap. May also be specified with the PROTOTEXT_DESCRIPTOR_SET environment variable.
  • -I, --proto-root <PROTO_ROOT> β€” root directory that .proto source files get resolved against for v's jump-to-definition (spec 0144). It shares its env var naming with PROTOTEXT_DESCRIPTOR_SET (spec 0090), and it's set externally by the internal prototools package embedding this repo. When neither this nor the env var is set, it falls back to <stub>/proto/ next to --descriptor-set (<stub> = the descriptor-set path with its extension stripped β€” the same stub reproto --schema-db-out uses), if that directory exists (spec 0155 G2). Still fully optional, bestie β€” v reports a message rather than failing at startup when no root is found either way. May also be specified with the PROTOTEXT_PROTO_ROOT environment variable.
  • -t, --type <TYPE> β€” the root message type. If you omit it, it's inferred automatically from --descriptor-set (which requires a hopcroft.rkyv scoring graph sitting next to it); and if inference is unavailable or inconclusive, the blob is rendered with no known type. 😌
  • --raw β€” skip root-type inference entirely and open the blob with no type at all, as raw wire bytes (spec 0168). Inference is the one startup phase whose cost scales with the size of the schema database rather than the blob, so on a large descriptor set this is the fast way in; it's also the way to look at a blob whose inferred type is wrong. You can still pick a type interactively afterwards, via the override pane.
  • --indent <INDENT> [default: 2] β€” number of spaces per nesting level in the rendered text.
  • --min-score <N> [default: 0] β€” the lowest score an inferred root type may have and still be used (spec 0389). It's an integer, negative allowed, or any for no floor. Below it, the blob opens with no type, same as on a tie; the override pane still lists every candidate though. A score is matches minus weighted penalties, so a negative one means the type contradicts the bytes more than it explains them 😭. Ignored with --type and --raw. Shares its env var with prototext. May also be specified with the PROTOTEXT_MIN_SCORE environment variable.
  • -j, --jobs <JOBS> [default: 80] β€” your CPU budget for root-type inference (spec 0217). Inference is the one startup phase whose cost scales with the size of the schema database rather than the blob, and it divides cleanly: the candidate types are partitioned and swept in parallel. 🧚

This is a ceiling for the whole session, not a target. It gets clamped to the number of CPUs actually available to the process (which respects a cgroup quota and an affinity mask), and while the TUI is running, one thread of it is left to the main loop. Defaults to every available CPU; 1 restores the single-threaded sweep.

  • --theme <THEME> [default: system] β€” the syntax-highlighting color palette (spec 0116 Β§9). system probes the terminal's actual background once at startup and resolves to dark or light. 🌈

Possible values:

  • dark
  • light
  • system
  • --override-preview-byte-budget <OVERRIDE_PREVIEW_BYTE_BUDGET> [default: 4096] β€” the max number of interior bytes of a live-preview override candidate handed to the renderer (spec 0174). It guards against a structurally mismatched candidate type making the recursive-descent decoder mis-parse arbitrary bytes into a pathologically large synthetic tree while you're just browsing candidates πŸ™ˆ. A truncated preview ends with a ... line. A confirmed override is always rendered completely, no matter what this value says.
  • --load-overrides <LOAD_OVERRIDES> β€” a previously-saved override collection (spec 0117 Β§4 YAML, the same file :save-overrides writes) to apply when the TUI opens. A target-hash mismatch is a warning (to stderr), not a hard error (spec 0354 S3). A missing file or malformed YAML is a hard error πŸ’€.

Only applicable to the interactive TUI (no subcommand). For batch override loading, see export --load-overrides.

  • --assume-binary β€” take the blob for wire bytes without even looking (spec 0216 S29).

Normally, a file whose first 13 bytes are #@ prototext: gets decoded from the textual form instead. This says don't, for the rare binary blob that happens to begin with those exact bytes.

  • --eager-read β€” read the blob into memory instead of mapping it (spec 0216 S29). πŸ‘‘

A large binary blob is mapped, which keeps its pages evictable rather than making them the process's own. The cost? The file must not change underneath the session: truncating it, or losing the network filesystem it lives on, turns a read into a SIGBUS rather than an error at startup. Use this for a blob that cannot be trusted to hold still.

Mapping is declined by itself for a small blob and for anything that isn't a regular file, so you only need this for the case the size test can't see.

  • --script <SCRIPT> β€” a guided walk through the blob to load (spec 0271). A missing or malformed file is a hard error.

With no --script, the blob path with its extension replaced by .script is loaded if it exists.

  • --no-script β€” do not look for a script beside the blob (spec 0271 S1).
  • --no-packing-penalty β€” don't charge records whose packing contradicts the schema's declaration (spec 0371). By default such a record scores net zero, which is right when blobs and schemas come from the same build; turn it off for a corpus whose writers ignore the declaration.
  • --script-height <SCRIPT_HEIGHT> β€” rows for the script pane, overriding its computed height: the script's tallest step, at most a third of the terminal (spec 0400 S1).
  • -h, --help β€” print help (see a summary with -h).
  • -V, --version β€” print version.
  • <BLOB> β€” the binary protobuf to decode. πŸ“

πŸŽ€ SUBCOMMANDS πŸŽ€

  • protolens-export(1) β€” export one node's rendering (or, for the two descriptor formats, its synthetic schema) and exit, without entering the interactive TUI.
  • protolens-quit(1) β€” run every startup phase and exit, without entering the interactive TUI (spec 0198) β€” this is the startup-time benchmark target. ⏱️
  • protolens-script(1) β€” apply every step of the loaded script and write what each one produced, without entering the interactive TUI (spec 0271 S14).
  • protolens-help(1) β€” print this message or the help of the given subcommand(s).

⭐ VERSION ⭐

v0.3.4


πŸ¦‹ ENVIRONMENT πŸ¦‹

  • PROTOLENS_COMPLETE β€” when set to bash, zsh, or fish, print a shell completion script to stdout and exit. ✨
  • PROTOLENS_GEN_MAN β€” when set to a directory, write this man page there as protolens.1 and exit.

πŸ’œ EXAMPLES πŸ’œ

Open a blob, inferring its root type from the descriptor set

protolens --descriptor-set schemas.desc message.binpb

Open a blob as raw wire bytes, skipping inference

protolens --raw message.binpb

Export one node without entering the TUI

protolens --descriptor-set schemas.desc message.binpb export /1/2

Enable bash completion

source <(PROTOLENS_COMPLETE=bash protolens)

🌟 SEE ALSO 🌟

prototext(1), reproto(1), protoscan(1)


and that's the whole page, bestie β€” no notes left behind 🫢 this one's from the User Commands corner of the General Commands Manual, page protolens, and yeah it's literally called PROTOLENS(1) in the header and the footer both. go decode something iconic πŸ’…

πŸ“¦ where this page comes from