Skip to content
Sırdaş

sirdas CLI

Terminal, scripts and CI. --json output on every command.

Start here

npx sirdas factura.pdf

For your AI agent

Paste this into Claude, ChatGPT or Cursor and the agent installs and configures itself by reading the Markdown version of this page.

Same engine as the web app and the MCP server, from the terminal. No network, no accounts, no telemetry.

Install

npx sirdas factura.pdf       # nothing to install but Node 20+
npm i -g sirdas              # or keep it around

From source:

git clone https://github.com/Brayan15p/SIRDAS-APP-PDF.git && cd SIRDAS-APP-PDF
npm install && npm run build -w packages/core -w packages/mcp -w packages/cli
node packages/cli/dist/main.js --help     # or: npm link -w packages/cli

Commands

# Start here: reads any file end to end (PDF, scan, DOCX, XLSX, PPTX, HTML, EPUB, CSV, EML, PNG/JPG)
sirdas <file>
sirdas leer      <file> [--json] [--no-anonymize] [--no-ocr] [--max-tokens 1500] [-o out.md]

# Ask a folder: the smallest cited context for a question
sirdas contexto  <folder|files...> -p "which contracts expire this quarter?" [--max-tokens 4000]
                 [--mantener FECHA] [--no-anonymize] [--ocr] [--json] [-o context.md]
                 [--indice folder.sirdas]   # opt-in: keep what was read so the next question converts nothing
sirdas olvidar   <index.sirdas>             # delete an index; refuses any other file
                 # ends with a numbers-only sentence you can share: no file names, no text

# Many documents to one table: cited fields, duplicates, totals that don't add up
sirdas campos    <folder|files...> [--tipo factura] [-o facturas.xlsx|.csv] [--force]
                 [--no-anonymize] [--ocr] [--json]

sirdas convertir <file.docx|xlsx|pptx|odt|epub|html|csv|eml|rtf|srt|vtt> [--json] [-o out.md]
sirdas separar   <batch.pdf> [-d dir] [--json]        # one PDF per document inside a batch
sirdas formulario <file.pdf> [--json]                  # filled form fields and checkboxes
sirdas classify  <file.pdf> [--json]                   # factura, contrato, historia_clinica…
sirdas revisar   <folder> [--sin-nombres]              # run everything over real files, report without content

sirdas pages     <file.pdf> delete|extract|rotate [--pages "2, 4-6"] [--angle 90] [-o out.pdf]
sirdas number    <file.pdf> [--format "Página {n} de {total}"] [--position bottom-right] [--skip-first 1]
sirdas watermark <file.pdf> --text CONFIDENCIAL [--opacity 0.15]
sirdas protect   <file.pdf> [--no-print] [--no-copy] [--no-edit] [-o out.pdf]   # asks for the password, or SIRDAS_PASSWORD
sirdas unlock    <file.pdf> [-o out.pdf]

sirdas markdown  <file.pdf> [--no-anonymize] [--json] [-o out.md] [--force]
sirdas ocr       <scan.pdf> [--lang spa+eng] [--lang-path dir] [--no-anonymize]
sirdas ocr --download-models [--lang spa]   # once; then it works offline
sirdas anonymize [file.txt] [--json] [--map map.json]  # reads stdin when no file
sirdas restore   [file.txt] --map map.json            # puts the real data back
sirdas chunks    <file.pdf> [--max-tokens 2000] [--json] [-d dir]
sirdas tables    <file.pdf> [--csv|--markdown|--json|--xlsx [-o out.xlsx]] [-d dir] [--delimiter ";"] [--lang es|en]
sirdas compare   <before.pdf> <after.pdf> [--all] [--json] [--ignore-case]
sirdas info      <file.pdf> [--json]
sirdas merge     <a.pdf> <b.pdf> [...] -o out.pdf [--force]
sirdas split     <file.pdf> [--ranges "1-3, 5, 8-end"] [-d dir] [--force]
sirdas compress  <file.pdf> [-o out.pdf] [--force]   # lossless

# Training data (all local, no model is ever called)
sirdas dataset       <a.pdf|b.docx|c.html> [...] [--format text|chat|prompt-completion|alpaca|sharegpt|langchain|llamaindex|embeddings]
                     [--hf]   # train/validation/test.jsonl + Hugging Face README.md
                     [--max-tokens 2000] [--no-anonymize] [--no-dedupe]
                     [--strip-boilerplate] [--split] [--seed s]
                     [--template "..."] [--system "..."]
                     [-d dir] [--no-meta] [--json]
sirdas dedupe        <a.pdf> <b.pdf> [...] [--threshold 0.8] [--json]
sirdas boilerplate   <a.pdf> <b.pdf> [...] [--min-words 5] [--json]
sirdas contamination <train.pdf> [...] --against <eval.pdf> [--n 13] [--json]
sirdas rl            <a.pdf> [...] [--max-per-table 10] [--lang es|en] [-o f.jsonl]
sirdas rl --reward-fn                                # the Python reward function
sirdas mcp                                           # start the MCP server over stdio
sirdas auditoria     <audit.jsonl> [--json]          # verify the SIRDAS_AUDIT_LOG hash chain and list files read and written
sirdas procedencia   <file> --registro <audit.jsonl> [--json]   # where a file came from, back to its originals

md is an alias of markdown.

On-disk index (opt-in)

Since 0.4.1.

sirdas contexto reads every file again on each run. With --indice <file> it keeps what it read in that file and, on the next run, converts only what changed (files are matched by sha256). The index exists only when you pass a path, and:

  • it contains the text of your documents: it is written with owner-only permissions (0600), and you should keep it like the originals;
  • it holds only what the last run read, so a file deleted from the folder leaves the index on the next run;
  • it is rebuilt when a different engine version wrote it;
  • it never overwrites a file that is not an index, and sirdas olvidar deletes an index and refuses any other file.

The MCP server does not write an index: build_context remembers files in the process only, so its tools stay read-only.

Conventions agents can rely on

  • Exit codes: 0 success · 1 usage error (bad flags, missing input, refusing to overwrite) · 2 the file could not be processed (password-protected, damaged, not a PDF). The reason is printed to stderr in one sentence.
  • stdout is the payload. markdown prints Markdown; with --json it prints one JSON object (markdown, pages, tokens_estimate, anonymized, redacted, has_text, source). Progress and warnings go to stderr.
  • Anonymization is on by default for markdown; --no-anonymize keeps the original data.
  • Never overwrites an existing file without --force.
  • anonymize --json includes the placeholder→value mapping; keep it local.

The anonymize → AI → restore round trip

Nothing is ever deleted. The original PDF is untouched and the mapping — which holds the real values — stays on your machine.

# 1. Anonymize, keeping the mapping
sirdas markdown historia.pdf --json | jq -r .markdown > anonima.md
sirdas anonymize anonima.md --map mapa.json > anonima-final.md

# 2. Send anonima-final.md to any model, then restore its answer locally
cat respuesta-de-la-ia.txt | sirdas restore --map mapa.json

A name always comes back whole: placeholders map to the complete original value, never a fragment.

Examples

# Markdown for an LLM, personal data replaced
sirdas markdown historia.pdf > historia.md

# Structured output for a script
sirdas markdown contrato.pdf --json | jq '.tokens_estimate, .redacted'

# Anonymize a snippet before pasting it anywhere
echo "Paciente: Ana Gómez, C.C. 52.123.456" | sirdas anonymize

# Split the first three pages and the last one
sirdas split informe.pdf --ranges "1-3, 8-end" -d ./partes

# Pull an invoice's line items into a spreadsheet (CSV carries a BOM for Excel)
sirdas tables factura.pdf --delimiter ";" -d ./tablas
sirdas tables extracto.pdf --xlsx          # one sheet per table, amounts as numbers

# Split a long document into chat-sized pieces
sirdas chunks informe.pdf --max-tokens 2000 -d ./partes

# Merge, then shrink losslessly
sirdas merge a.pdf b.pdf -o todo.pdf && sirdas compress todo.pdf

Docker

For machines without Node, or an isolated network. The image has the OCR models inside and needs no network at run time:

docker run --rm --network none -v "$PWD:/work" ghcr.io/brayan15p/sirdas factura.pdf
docker run --rm -i -v "$PWD:/work" ghcr.io/brayan15p/sirdas mcp   # MCP over stdio

The image is published to GHCR by the release workflow with every version. You can also build it from the repository's Dockerfile with docker build -t sirdas ..