Section 1: Types & Errors ✅
src/types.ts — ToolResponse, ToolContext, ToolDefinition, FileReference, etc.
src/errors.ts — NutrientApiError, FileError, ConfigError, formatError()
Section 2: Client & Files ✅
src/client.ts — makeClient() HTTP client with credit header extraction
src/files.ts — readFileReference, buildFormData, resolveReadPath, writeResponseToFile
Section 3: Document Processing Tools ✅
src/tools/convert-to-pdf.ts — nutrient_convert_to_pdf tool
Supports DOCX, XLSX, PPTX, HTML, images → PDF
Page ranges, password-protected files, HTML layout options (orientation, size, margin)
src/tools/convert-to-image.ts — nutrient_convert_to_image tool
PDF → PNG, JPEG, or WebP with optional DPI, width, height, page ranges
src/tools/convert-to-office.ts — nutrient_convert_to_office tool
PDF → DOCX, XLSX, or PPTX
src/tools/ocr.ts — nutrient_ocr tool
OCR action with configurable language, produces searchable PDF
src/tools/watermark.ts — nutrient_watermark tool
Text watermarks: text, fontColor, fontSize, opacity, rotation
Image watermarks: separate image file added to FormData
All tools: assertOutputDiffersFromInput, credit logging, formatError wrapping
TypeScript compiles clean (npx tsc --noEmit passes)
Section 4: Extraction Tools ✅
src/tools/extract-text.ts — nutrient_extract_text tool
Three modes: text (plainText), tables, key-values (keyValuePairs)
Defaults: mode=text, language=english
Returns JSON inline (no file output)
Credits logged, errors formatted
TypeScript compiles clean (npx tsc --noEmit passes)
Section 5: Redaction Tools ✅
src/tools/redact.ts — nutrient_redact tool
Three strategies: preset (13 built-in patterns), regex, text
Chains createRedactions → applyRedactions via /build endpoint
Strategy-specific validation (preset/regex/text required fields)
Correct caseSensitive defaults (true for regex, false for text)
Optional startPage/pageLimit for scoped redaction
src/tools/ai-redact.ts — nutrient_ai_redact tool
Uses /ai/redact endpoint (NOT /build)
FormData with file1 (blob) + data (JSON with documents/criteria)
5-minute timeout (300,000ms) for AI analysis
Rejects URL inputs (requires local file)
Natural-language criteria, defaults to "All personally identifiable information"
Both tools: assertOutputDiffersFromInput, credit logging, formatError wrapping
TypeScript compiles clean (npx tsc --noEmit passes)
Section 6: Signing Tool ✅
src/tools/sign.ts — nutrient_sign tool
Calls /sign endpoint (not /build) with its own FormData format
FormData fields: file (PDF blob), data (JSON signature options)
Optional watermark and graphic image attachments
CMS (default) and CAdES signature types with configurable level
Visible signatures (pageIndex + rect → position + appearance) or invisible (omit both)
Signature metadata: signerName, signatureReason, signatureLocation
URL inputs rejected (local file required)
Helper buildSignatureOptions() extracted for clarity
Credits logged, errors formatted
TypeScript compiles clean (npx tsc --noEmit passes)
Section 7: Credit Tracking ✅
src/tools/check-credits.ts — nutrient_check_credits tool
src/credits.ts — JsonlCreditTracker implementation
Section 8: Plugin Entry Point ✅
index.ts — Full entry point wiring all 10 tools
Imports all 10 tool modules with correct export names
Resolves API key: config → env → lazy ConfigError on first use
Creates shared ToolContext (client, credits, sandboxDir)
Registers all 10 tools via api.registerTool() loop
Missing API key does NOT prevent plugin load (lazy proxy client)
Returns { name: 'nutrient', version: '0.1.0' }
TypeScript compiles clean (npx tsc --noEmit passes)
Section 10: README and Documentation ✅
README.md — Comprehensive documentation
Installation via openclaw plugins install and npm
Configuration: API key (config + env var), sandbox directory
Quick start with example agent conversations
All 10 tools documented with parameter tables and JSON examples
Credit tracking explanation (balance + usage)
Sandbox mode documentation
Error handling reference
Links to Nutrient dashboard, API docs, npm, OpenClaw
MIT license badge
LICENSE — MIT license (verified, already existed)