DeckProbe routes local files, raw stdin bytes, and JSONL records through the same source-independent engine. A logical filename extension selects the PDF, Microsoft Office, or modern Apple iWork path; DeckProbe then verifies the container and internal type, executes only the paths needed for the requested targets, and emits structured JSON.
deckprobe [OPTIONS] <INPUT>
deckprobe --jsonl [OPTIONS]
deckprobe <COMMAND> [OPTIONS]
Run deckprobe -h for a compact option list or deckprobe --help for selector details, examples, and exit statuses. Every discovery command also has its own long help:
deckprobe formats --help
deckprobe targets --help
deckprobe generate --help
deckprobe schema --help
deckprobe completion --help
deckprobe install --helpInspect a document with the default metadata-level probe:
deckprobe report.pdfRequest a specific target and pretty-print the report:
deckprobe -t slide_count --pretty deck.pptxRequest several targets in one pass:
deckprobe \
-t format,title,page_count \
report.pdfThe target option is repeatable. Use short target names after the input format has been detected:
deckprobe -t title -t page_count report.pdf
deckprobe -t title,page_count report.pdfInspect every target available to the deep profile:
deckprobe -l d -t @all workbook.xlsxPreview the selected execution paths without executing driver probe paths:
deckprobe -P -p report.pdfTreat unresolved targets as a failed command while retaining the JSON report:
deckprobe -s -t format,page_count report.pdfReturn a compact target-to-value envelope when evidence details are not needed:
deckprobe -t @summary --view values report.pdfProbe bytes from stdin using a logical filename with an extension:
cat report.pdf | deckprobe -n report.pdf -Probe several paths from JSONL:
printf '%s\n' '{"path":"report.pdf"}' '{"path":"deck.pptx"}' \
| deckprobe --jsonl -t @summarySingle-input probes, discovery, and failed commands write exactly one JSON
value to standard output. JSONL mode writes one compact JSON value per non-empty
input line. Probe reports use schema version 2 and contain these top-level
fields:
schema_version tool_version status input driver results execution diagnostics
resultsis keyed by target name. Each result includes its status, confidence, selected path, and source; resolved results also containvalue.statusisokwhen every requested target satisfies the request, orpartialwhen one or more results are unresolved or below the requested confidence.executionrecords the probe level, selected paths, estimated and actual cost, unresolved targets, and any zero-additional-pathpiggyback_targets.diagnosticscontains structured warnings produced while planning or probing.--prettychanges whitespace only; it works before or after theformatsandtargetssubcommands.- Failures use
status: "error"and anerrorobject containing stablecode,message, andexit_codefields. - Default reports are deterministic:
actual_costincludes byte and seek counters but omits wall-clock time.--telemetryopts intoelapsed_ms. - With
--strict, DeckProbe still writes the complete report to standard output, then exits with status5if any requested target is unresolved. --view valuesreturnsschema_version, input/driver identity, a compactvaluesmap, unresolved targets, and diagnostics. The default--view fullkeeps the complete evidence report.
For scripts, check the exit status before consuming standard output unless status 5 is an expected result.
The default positional input is a regular local file. The report uses
source_kind: "local_file" and preserves the basename as display_name.
Use positional - and provide -n/--stdin-name NAME. The name must contain the
extension used for routing; --input-format remains only an assertion and does
not replace it. Stdin is buffered at the CLI boundary and rejected as soon as it
exceeds the active physical-byte budget.
cat workbook.xlsx | deckprobe -n workbook.xlsx -The report uses source_kind: "stdin".
--jsonl reads stdin one line at a time. Each non-empty line may be:
"/absolute/or/relative/report.pdf"
{"path":"report.pdf"}
{"name":"upload.pdf","data_base64":"JVBERi0xLjcK"}name may override the display/routing name of a path record. A byte record
requires both name and data_base64; base64 is accepted as an alias.
Global target, confidence, format-option, budget, strict, plan, and view options
apply to every record. Pretty output conflicts with JSONL because each output
must remain on one line. Record errors are emitted in place and later records
continue; the process exits with the highest record exit status.
Pass one or more short target names to repeatable -t/--targets; values may
also be comma-separated. The input filename extension supplies the format, so
the examples do not repeat a format prefix. The default selector is @default.
Reports and discovery output retain stable canonical target keys for machine
consumers; those keys are omitted from the interactive examples below.
| Selector | Expands to |
|---|---|
@header |
Header-level identity targets |
@default |
The driver's defaults for the active --probe-level |
@summary |
Identity, common metadata, and primary format structure |
@security |
Encryption, macro, signature, external, and active-content signals |
@structure |
Format-owned counts, names, dimensions, and structure |
@assets |
Asset, preview, image, media, font, and embedded-object targets |
@quality |
Integrity, repair, extension, and conformance targets |
@format |
Format-specific targets available at the active level |
@all |
Every target available at the active level |
@summary deliberately omits a format statistic when the current driver can
only obtain it through a full-file path. For example, request PDF page count
through @structure or page_count until a range-aware page-tree path is
available.
Target names and presets may be mixed:
deckprobe -t @header,title,page_count report.pdf
deckprobe -t @summary -t @security report.pdfOptional targets are returned only when a path already selected for a required target produces them at the requested confidence. They never add another path and do not make the report partial when absent:
deckprobe -t page_count -o object_count report.pdf
deckprobe -t page_count -o object_count -N report.pdfDiscover the exact targets, minimum levels, value types, and format options for a profile with targets:
deckprobe targets --format pdf --pretty
deckprobe targets pdf --pretty
deckprobe targets --format docx --pretty
deckprobe targets --format xlsx --pretty
deckprobe targets --format pptx --pretty
deckprobe targets --format key --pretty
deckprobe targets --format numbers --pretty
deckprobe targets --format pages --prettyAccepted format names include pdf, word/docx/docm, excel/xlsx/xlsm, powerpoint/pptx/pptm, keynote/key, numbers, pages, and legacy/doc/xls/ppt.
--probe-level/--level (-l) controls both the resource budget profile and
which probe paths are eligible:
| Level | Intended use |
|---|---|
header |
Container identity and header-level properties |
metadata |
Bounded document metadata and common structural counts; this is the default |
deep |
Higher-cost paths needed by deep targets |
Levels also accept h/m/d, l0/l1/l2, and 0/1/2.
--minimum-confidence/--confidence (-c) filters eligible paths. Its values,
in increasing order, are low, medium, high, and exact; l/m/h/x are
accepted shorthands and the default is high.
Use repeatable -C/--target-confidence TARGET=LEVEL for individual overrides. A
short target alias is accepted when it is unambiguous:
deckprobe -t slide_count,orientation \
-C slide_count=x \
deck.pptxAn explicitly named target can be valid for the detected format but unavailable at the chosen level or confidence. If some other requested target can be planned, the report records the unavailable target under execution.unresolved_targets. If no requested target has an eligible path, DeckProbe exits with status 1 as an unsupported-target request.
confidence describes how strong the evidence for one value is, as judged by the path that
produced it. It is not a measured accuracy rate.
| Label | Score | What normally backs it |
|---|---|---|
exact |
1.0 |
Read directly from the authoritative structure in the container |
high |
0.95 |
A statistic the authoring application saved, such as the slide count in docProps/app.xml. Authoritative unless that application left it stale |
medium |
0.7 |
Inferred from a proxy, such as counting xl/worksheets/sheet*.xml parts instead of reading the workbook's declared sheets |
low |
0.4 |
Weak or indirect evidence |
none |
0.0 |
Accompanies a result that carries no value |
confidence_score is a fixed constant per label, not a calibrated probability. 0.95 does not
mean the value is correct 95% of the time on real-world files; no corpus measurement backs these
numbers. Use them to order or threshold results, never to report an accuracy figure to a user.
The report's own status is ok or partial. A result's status is one of eight values, and the
two answer different questions.
partial means at least one requested target could not be resolved at the requested confidence. It
says nothing about whether the document is damaged or unsafe — the remaining results are still
valid.
deckprobe -t slide_count,author --pretty deck.pptxThe slide count here is perfectly good. Treating partial as a failure would discard it.
Contrast that with a structural target the format cannot answer at all:
deckprobe -l d -t corrupted report.pdf # exits 1corrupted and missing_assets are declared for every modern format, but only the iWork drivers
implement a path for them. Naming one on a PDF or OOXML file is an unsupported-target request, so
DeckProbe exits 1 rather than returning a report. Use the @quality selector to get whatever the
active driver actually supports.
Result status |
Carries value |
Meaning |
|---|---|---|
resolved |
yes | Obtained at or above the requested confidence |
estimated |
yes | Obtained, but an estimate |
unknown |
no | The path ran; the document does not record this fact. A normal answer, not an error |
unsupported |
no | This format has no path for the target |
invalid |
no | The document records something that fails validation |
budget_exceeded |
no | A limit stopped this target specifically |
failed |
no | The path errored |
planned |
no | --plan-only only |
Distinguish "value": null on a resolved result — the field exists and is empty, which is an
answer — from status: "unknown", where the probe could not answer.
Use --strict when an unresolved target must fail the command; it exits 5 and still writes the
full report.
DeckProbe uses the normalized filename extension to select a format path, then verifies its signature and internal type. Renaming a PPTX to DOCX, for example, returns MALFORMED_INPUT. -f/--input-format adds another assertion; it does not force an unrelated parser onto the file:
deckprobe --input-format pdf report.pdf
deckprobe --input-format powerpoint deck.pptx
deckprobe --input-format iwork deck.keyFor .key, .numbers, and .pages, validation requires Index/Document.iwa, Metadata/Properties.plist, and the expected IWA root-object family. At deep, the bounded Snappy/Protobuf path scans every IWA entry and exposes archive/message-type inventories plus stable Keynote slide state, Numbers table models, and Pages page/text structure. Legacy XML iWork packages remain outside the support boundary and return UNSUPPORTED_FORMAT with a message that modern IWA is required.
Pass driver settings with repeatable namespaced KEY=VALUE arguments. Query deckprobe targets --format FORMAT for the live option list, allowed values, and defaults:
deckprobe \
-O repair_xref=safe \
-O max_objects=50000 \
report.pdf-O/--option is an alias for --format-option. After driver detection, an
unambiguous local key can omit its namespace:
deckprobe -O repair_xref=safe -O max_objects=50000 report.pdfWhen the same option is repeated, the last value wins. Unknown options and values are rejected by the selected driver.
The level profile supplies defaults, and these options override individual limits:
| Option | Limit |
|---|---|
-b / --probe-size BYTES |
Physical bytes read by probe paths; --probesize is an alias |
-x / --max-expanded-bytes BYTES |
Cumulative decompressed bytes |
-e / --max-archive-entries COUNT |
ZIP/OPC entry count |
-T / --timeout-ms MILLISECONDS |
Wall-clock probe budget |
A budget violation exits with status 4. The successfully consumed cost is reported under execution.actual_cost when a report can be produced.
The built-in defaults are designed for a fast CLI response: 500 ms at header, 500 ms at metadata, and 5 seconds only for an explicitly selected deep probe. Header allows up to 4 MiB of physical and expanded data and 4,096 archive entries so realistic iWork central directories and Document.iwa can be validated. These are cooperative hard bounds on DeckProbe I/O and parsing checkpoints; callers that need a process-level deadline should still enforce one around the CLI.
List the supported drivers, profiles, and support boundaries:
deckprobe formats --prettyList the target and format-option schemas for one profile:
deckprobe targets --format pdf --pretty
deckprobe targets pdf --prettyDiscovery includes each target's compatibility value_type, JSON Schema
fragment, aliases, selector membership, minimum level, cost class, and complete
selector expansions for header, metadata, and deep.
Print the exact report schema bundled into the running binary or generate shell completion source:
deckprobe schema --pretty
deckprobe completion bash > deckprobe.bash
deckprobe completion zsh > _deckprobe--pretty is a global output flag, so both placements are valid:
deckprobe --pretty formats
deckprobe formats --prettydeckprobe install writes support files into a local directory. Where generate man and
completion emit to standard output, install resolves a conventional destination and applies one
policy to everything it writes: an idempotent created/updated/unchanged comparison, a --force gate,
--dry-run, and a single JSON receipt.
deckprobe install # the default artifact set: the agent skill
deckprobe install --skills --dry-run --pretty # preview, writing nothing
deckprobe install --skills --agent claude --global # ~/.claude/skills/deckprobe/
deckprobe install --skills --dir ./.claude/skills # explicit skills container
deckprobe install --man --global
deckprobe install --completions zsh --dir ~/.zfuncSelectors combine, and each resolves its own destination, so --skills --man installs both in one
run. With no selector at all, the default set is installed, which today is --skills.
| Selector | Default destination | With --dir D |
|---|---|---|
--skills |
the skills directory for each resolved --agent |
D is the skills container; the skill lands in D/deckprobe/ |
--man |
./man, or $XDG_DATA_HOME/man/man1 (else ~/.local/share/man/man1) with --global |
files land directly in D |
--completions SHELL |
none — --dir is required, because user completion directories are not standardized |
files land directly in D |
--agent is repeatable and comma-separated. --dir bypasses it entirely and conflicts with both
--agent and --global.
| Agent | Project | User (--global) |
|---|---|---|
claude (alias claude-code) |
.claude/skills |
~/.claude/skills |
codex (alias codex-cli) |
.agents/skills |
~/.codex/skills |
cursor |
.agents/skills |
~/.cursor/skills |
opencode |
.agents/skills |
~/.config/opencode/skills |
gemini (alias gemini-cli) |
.agents/skills |
~/.gemini/skills |
copilot (alias github-copilot) |
.agents/skills |
~/.copilot/skills |
windsurf |
.windsurf/skills |
~/.codeium/windsurf/skills |
cline, zed, agents (alias universal) |
.agents/skills |
~/.agents/skills |
auto is the default: it selects every agent whose directory already exists at the chosen scope and
falls back to the vendor-neutral agents layout when none does. all selects every row. Several
agents share .agents/skills, so destinations are deduplicated and the receipt lists every agent
served by each one.
DeckProbe deliberately does not track the full ecosystem of agent directories. For anything outside
this table, use --dir, or install through the skills CLI, which maintains a much larger table:
npx skills add deckflow/deckprobe -a <agent>{
"schema_version": 2,
"tool_version": "2.3.1",
"status": "ok",
"install": {
"artifacts": ["skills"],
"scope": "project",
"dry_run": false,
"force": false,
"targets": [
{
"artifact": "skills",
"name": "deckprobe",
"agents": ["claude"],
"directory": "./.claude/skills/deckprobe",
"files": [{ "path": "SKILL.md", "bytes": 9069, "action": "created" }],
"orphaned": []
}
]
}
}- A file whose contents already match is reported
unchangedand is not rewritten, so re-runninginstallis a safe no-op. - A skill directory DeckProbe previously wrote is recognized by a marker in its
SKILL.mdand is refreshed in place, so upgrading needs no--force. - A
SKILL.mdwithout that marker belongs to somebody else. The command fails with exit1and writes nothing at all — including for other agents in the same run — until--forceis given. orphanedlists files in the destination that this version no longer ships. They are reported, never deleted.--dry-runperforms the same validation and produces the same receipt without writing.
Every destination is resolved and validated before anything is written, so a rejected run leaves no half-installed tree behind -- across artifacts as well as across agents.
Exit statuses follow the table below: 1 for a refused overwrite, a missing --dir for
--completions, or an unresolvable home directory; 2 for a contradictory flag combination or a
write failure.
The skill this installs is the same content published at github.com/deckflow/deckprobe, so
npx skills add deckflow/deckprobe and /plugin marketplace add deckflow/deckprobe deliver
identical bytes.
| Status | Meaning |
|---|---|
0 |
Success. Unresolved targets are allowed unless --strict is used. |
1 |
Invalid request or unsupported target. This includes a missing input argument. |
2 |
Command-line syntax error or source I/O error. |
3 |
Unsupported or unrecognized input format. |
4 |
Malformed input or probe budget exceeded. |
5 |
At least one requested target is unresolved and --strict was used. A JSON report is still written. |
6 |
Internal parser or report-serialization failure. |
Syntax and runtime failures use the same stable, script-friendly JSON shape on standard output:
{
"schema_version": 2,
"tool_version": "2.2.0",
"status": "error",
"error": {
"code": "MALFORMED_INPUT",
"message": "malformed input: .docx package is missing required main part word/document.xml",
"exit_code": 4
}
}Human help and version output remain normal text for --help and --version.
Generate the main roff manual page from the same command model as --help:
deckprobe generate man > deckprobe.1
man ./deckprobe.1For packaging or a local MANPATH, generate the main page and one page for each subcommand:
deckprobe generate man -d ./man
man -M ./man deckprobe
man -M ./man deckprobe-targetsThe generator creates its output directory when needed and writes
deckprobe.1, deckprobe-formats.1, deckprobe-targets.1,
deckprobe-generate.1, deckprobe-schema.1, deckprobe-completion.1, and
deckprobe-install.1.
deckprobe install --man writes the same set into a conventional location and reports the result as
JSON. See Installing agent assets.
{ "status": "partial", // because author could not be resolved "results": { "powerpoint.slide_count": { "status": "resolved", "value": 31, "confidence": "high", "path": "powerpoint.app_statistics", "source": "docProps/app.xml saved statistic" }, "document.author": { "status": "unknown", // the path ran; the file records no author "confidence": "none" } }, "execution": { "unresolved_targets": ["document.author"] } }