Files
magnus919_agent-skills/anydoc/references/cli-reference.md
T
Magnus HedemarkGitHubfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
f37dc73829 feat(skill): add anydoc — office documents to GitHub-Flavored Markdown (#295)
* feat(skill): add anydoc core content and references

Add the anydoc skill content tree: SKILL.md (progressive-disclosure index
with frontmatter per ALLOWED_FIELDS), human-facing README, the five reference
files (formats, cli-reference, errors, workflows, sources), 24 committed
fixtures (valid + error cases), and a fixture-grounded eval manifest with 8
cases. Every documented behavior, exit code, and error message was verified
against the real pinned CLI (npx -y @firecrawl/anydoc@0.1.6); verbatim --help
and error transcripts are reproduced character-for-character.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

* feat(skill): add anydoc wrapper script and unit tests

Implements scripts/anydoc, a stdlib-only Python wrapper around the pinned
@firecrawl/anydoc@0.1.6 CLI: convert/batch/info subcommands, global
--json/--dry-run, input and output pre-validation, friendly hints for the
no-OCR/encrypted/malformed/unsupported error classes, Node >= 20 and npx
availability checks, deterministic batch output naming with documented
duplicate/collision behavior, and exit codes 0/1/2. Adds offline unittest
suite (46 tests, real-CLI tests skip when npx is unavailable) and keeps the
wrapper contract documented in cli-reference.md and errors.md.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

* feat(skill): ratchet anydoc evals to 14 grounded cases

Verify the pre-authored 8-case manifest and extend it with six
high-signal cases (PDF lower-fidelity pipeline, legacy .ppt table
flattening, ODP same-serializer, RTF, EPUB, CSV header promotion),
each grounded in real pinned-CLI runs against the committed fixtures.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

* feat(skill): integrate anydoc into repo catalog and artifacts

Add the sorted anydoc catalog entry to README.md (between agent-skills
and api-design-and-evolution), regenerate the tracked catalog artifacts
(.claude-plugin/marketplace.json, .codex-plugin/plugin.json,
.agents/plugins/marketplace.json, llms.txt) with the ruby generators,
and add a routing note to documents/SKILL.md pointing office-document
to-markdown conversion at the anydoc skill.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

* fix(skill): polish anydoc wrapper timeout, JSON shape, and docs

- run_cli raises CliTimeoutError on the 120s timeout; convert/batch with
  --json now emit one parseable JSON error envelope (error_class "timeout")
  on stdout before exiting, so --json always yields exactly one JSON doc
- batch JSON failure entries (pre-validation and CLI) now carry error_class
  ("io" for missing/dir inputs, mapped classes for CLI failures), so all
  batch failure entries share the same shape
- build_cli_command places -o/-f before the -- separator for dash-leading
  filenames, so `convert -f csv -- -weird` converts instead of misparsing
  ("unexpected second input"); absolute-path inputs unchanged
- workflows.md vault-ingestion recipe globs notes/* instead of docs/* and
  warns to run from a temp/vault dir, never touching repo-root docs/
- unit tests: +6 (timeout envelope x4, batch error_class shape,
  dash-leading filename); suite grows 46 -> 52

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

---------

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-06 20:11:19 -04:00

10 KiB
Raw Blame History

CLI reference: the Any Doc CLI (pinned @firecrawl/anydoc@0.1.6)

Everything here was captured by running the pinned CLI on this machine (npx -y @firecrawl/anydoc@0.1.6, version 0.1.6, Node v22). The CLI is a 4.7 KB Node wrapper (bin.anydoc = cli.js) around a native NAPI binding that ships as an npm optionalDependency per platform.

Verbatim --help output

anydoc: convert documents to GitHub-Flavored Markdown

Usage:
  anydoc <file> [options]
  anydoc - [options] < file

Converts one document per invocation and writes the Markdown to stdout.
Pass - as the input to read the document from stdin. Never prompts; all
diagnostics go to stderr.

Options:
  -o, --output <path>    Write the Markdown to <path> instead of stdout
  -f, --format <format>  Name the input format instead of detecting it:
                         doc, docx, odt, pdf, ppt, pptx, rtf, epub, xlsx, ods, odp, csv
                         (extension aliases like xls, docm, ppsx resolve
                         to these)
  -h, --help             Print this help and exit
  -V, --version          Print the version and exit

The format is detected from the file content; the file extension is the
fallback for signature-less formats (CSV). stdin has no extension, so CSV
input from stdin needs --format csv. Scanned or image-only PDFs need OCR,
which anydoc does not do, and error as unsupported.

Exit codes:
  0  success
  1  the document could not be read or converted
  2  usage error: unknown option, missing input, or invalid --format

Examples:
  anydoc report.docx
  anydoc slides.pptx -o slides.md
  anydoc - --format csv < data.csv
  curl -s https://example.com/paper.pdf | anydoc -

anydoc --version prints exactly 0.1.6 (verified; both --help and --version exit 0 and write to stdout).

Invocation forms

anydoc <file> [options]        # convert a path on disk
anydoc - [options] < file      # read the document from stdin
  • - as the input reads the document from stdin.
  • The CLI accepts exactly one document per invocation — there is no batch mode. Passing a second input exits 2: anydoc: one document per invocation: unexpected second input '<path>'. For multiple documents use a shell loop or scripts/anydoc batch (see workflows.md).

Flag reference

Token Behavior (verified)
<file> Input path. Format detected from content; extension is the fallback for signature-less formats (CSV).
- Read the document from stdin. If stdin is a TTY, exits 2 with anydoc: stdin is a terminal; pipe or redirect a document into anydoc -.
-o <path>, --output <path> Write the Markdown to <path> instead of stdout. Silently overwrites an existing file (verified). Writing to a directory fails with exit 1: anydoc: EISDIR: illegal operation on a directory, open '<path>'. With -o, stdout stays silent.
-f <fmt>, --format <fmt> Force the input format instead of detecting it. Values: doc, docx, odt, pdf, ppt, pptx, rtf, epub, xlsx, ods, odp, csv. Extension aliases resolve through the parser mapping (verified: --format xls, --format docm accepted). Invalid value → exit 2: anydoc: invalid format 'bogus'; expected one of: doc, docx, odt, pdf, ppt, pptx, rtf, epub, xlsx, ods, odp, csv.
-h, --help Print help to stdout, exit 0. Works even when the native binding is unavailable.
-V, --version Print the version (0.1.6) to stdout, exit 0. Binding-independent like --help.
--format=x Inline = value syntax is supported for long options (verified: --format=rtf works).
-- End of options: everything after -- is treated as a positional input (a filename starting with -).
Missing option value anydoc: <option> requires a value → exit 2 (e.g. anydoc: -o requires a value).
Unknown option anydoc: unknown option '--bogus' (see anydoc --help) → exit 2.
No input anydoc: missing input: pass a document path, or - for stdin (see anydoc --help) → exit 2.

stdin / stdout / stderr conventions

  • stdin input via -. Because stdin has no file extension, CSV from stdin requires --format csv (CSV has no content signature). Without it, CSV bytes fail with exit 1: anydoc: unsupported input: unrecognized file content: name the format explicitly. Verified success pattern:

    printf 'name,role\nAlice,Engineer\n' | npx -y @firecrawl/anydoc@0.1.6 - --format csv
    
  • Markdown goes to stdout only. With -o, stdout stays silent.

  • All diagnostics go to stderr as exactly one anydoc: <message> line per failure. Nothing is ever printed to stdout on failure.

  • The CLI never prompts — no confirmation, no interaction. (-y on the npx invocation exists only to answer npx's package-install prompt.)

  • EPIPE is handled: if the downstream pipe closes early (anydoc big.xlsx | head -n 1), the CLI exits 0 with no stderr noise (verified). Piping into head is not treated as a conversion failure.

  • No environment variables — the CLI uses only argv, stdin, and the filesystem (verified by reading cli.js).

Running it: npx invocation

npx -y @firecrawl/anydoc@0.1.6 report.docx                # markdown to stdout
npx -y @firecrawl/anydoc@0.1.6 slides.pptx -o slides.md   # to a file
npx -y @firecrawl/anydoc@0.1.6 - --format csv < data.csv  # stdin (CSV needs --format)
curl -s https://example.com/paper.pdf | npx -y @firecrawl/anydoc@0.1.6 -   # URL → stdin

Version pinning

Always pin the version: npx -y @firecrawl/anydoc@0.1.6. An unpinned npx -y @firecrawl/anydoc floats to the latest published tag, so conversions are not reproducible across time. All behavior in this skill is documented against 0.1.6. The -y flag answers npx's "Ok to proceed?" install prompt non-interactively; without it, bare npx @firecrawl/anydoc will prompt on a cold cache.

First run and offline behavior

  • The first npx invocation downloads the npm package plus the native platform binary (network required once). Verified with a fresh empty npm cache: env npm_config_cache=$(mktemp -d) npx -y @firecrawl/anydoc@0.1.6 --version prints 0.1.6 and exits 0.
  • Later runs reuse the npm cache; measured warm startup is ~0.330.55 s per invocation (see workflows.md).
  • Cold-cache offline: if the package is not cached and there is no network, npx itself fails with a clear fetch error before anydoc runs. The conversion itself is fully local — only package retrieval needs network.
  • Permanent / offline-capable alternative: npm install -g @firecrawl/anydoc once, then invoke anydoc directly (still pinning is up to you). This satisfies the skill's "no service dependency" claim: there is no server, no API key, and no upload — the only network use is downloading the tool.

Distribution and system requirements

  • Node.js >= 20 (package engines). Verified under Node v22.
  • The native binary ships via npm optionalDependencies — one small package per platform (darwin-x64, darwin-arm64, linux-x64-gnu, linux-arm64-gnu, linux-x64-musl, linux-arm64-musl, win32-x64-msvc), with no postinstall script and no compilation.
  • The npm package @firecrawl/anydoc 0.1.6 is ~48 KB unpacked (the binding package is a few MB per platform); published 2026-08-05T18:29:40Z.
  • The Rust crate anydoc (crates.io) and Python wheels firecrawl-anydoc (PyPI, imports as anydoc, Python >= 3.10) ship in the same release train. There is no standalone Rust CLI binary (cargo install anydoc is an open feature request) — the CLI exists only through the npm package.

The wrapper: scripts/anydoc

The skill ships a Python 3 standard-library wrapper at scripts/anydoc that delegates to the pinned CLI. It adds value beyond a thin npx alias:

  • convert <file|-> [-o out.md] [-f <format>] [--json] [--dry-run] — pre-validates the input path (missing file, directory input) and the -o path (existing directory) before invoking the CLI, validates -f against the 21 accepted format names (the 12 canonical parsers plus the 9 aliases, exit 2 on an invalid name), maps known failure classes to friendly hints (no-OCR, encrypted, malformed, unsupported), and forwards the CLI's exit code. Stdin input via - is passed straight through. A dash-leading filename is supported through the CLI's -- marker with the options first: anydoc convert -f csv -- -weird (the wrapper emits -o/-f before --, since npx forwards -- to the CLI and anything after it reads as an extra input). Absolute paths never need this.
  • batch <inputs...> [--out-dir DIR] [--json] [--dry-run] — converts many documents one at a time, prints per-file status, continues past failures, and exits 1 when any input failed. Output naming is deterministic: each input becomes <stem>.md under --out-dir, which is created when missing and defaults to the current working directory. Duplicate inputs convert per occurrence (a later conversion overwrites the earlier output); same-basename inputs from different directories collide on the same <stem>.md and the last one wins.
  • info [--version] — reports the tool name and the pinned CLI version (anydoc 0.1.6 (wraps @firecrawl/anydoc@0.1.6)) without invoking the converter; info --version prints exactly 0.1.6.
  • Global --json (exactly one JSON document on stdout; diagnostics stay on stderr) and --dry-run (print what would run — the exact npx command line and output paths — and execute nothing: no CLI spawn, no output files, no directory creation). With --json, convert embeds the converted markdown in the JSON document when -o is not given.
  • Checks for Node >= 20 (missing node, or a version below 20, exits 1 with a clear message naming Node.js and the required version) and for npx (missing npx exits 1 naming npx and the pinned package @firecrawl/anydoc@0.1.6); always invokes npx with -y; never prompts; exit codes 0/1/2 mirror the CLI.

Run it as anydoc/scripts/anydoc <subcommand> ... from the repository root, scripts/anydoc <subcommand> ... from the skill directory, or python3 anydoc/scripts/anydoc <subcommand> ... anywhere (the executable bit and #!/usr/bin/env python3 shebang let it run directly). See workflows.md for recipes and errors.md for the error vocabulary.