Skip to main content
Mesh’s standard release reads Slack DOCX, embedded-text PDF and UTF-8 TXT attachments out of the box. Every Slack agent gets list_documents and read_document; no parser image, environment variable, execution backend, third-party account or per-agent opt-in is required. Files shared earlier in the conversation are eligible too, subject to current authorization.

Default processing path

The release embeds a fixed Go document parser compiled to WebAssembly/WASI. The control plane passes authorized attachment bytes to a fresh wazero instance and receives bounded JSON. The worker has:
  • No filesystem mounts, host paths, environment, credentials or socket API.
  • No shell, child processes, arbitrary commands or model-supplied executable code.
  • 256 MiB maximum linear memory, a 45-second execution deadline, and at most two active document workers per Mesh process.
  • Immediate busy/retry error when both slots are occupied; no unbounded queue retaining uploads or consuming another document’s execution budget.
  • 8 MiB input, 4 MiB JSON output, 500 PDF pages, 2,000 archive entries, 32 MiB declared/actual DOCX expansion, and 128 XML nesting levels.
  • Rejection of encrypted/duplicate archive entries, DTD/entities and unsupported XML encodings. Relationships, macros and external resources are not resolved.
The deadline interrupts even a worker stuck in a CPU loop. Output is bounded at its host writer, not after collecting an unlimited buffer. Instances are closed on success, failure or cancellation. Aggregate linear memory is bounded to 512 MiB; this is not a total process RSS limit (Go, compiled code, buffers and other runtime work also consume memory). Deployments must budget for that overhead. WASM validation, wazero and its WASI implementation are part of the trusted computing base; this is not a separate OS-process boundary. This is a deliberately narrow built-in capability, not an agent execution backend granting ambient access to the control-plane host. The standard image remains non-root and distroless, with no writable filesystem or additional services required. Parsing libraries are imported only by the worker, never used on untrusted content in the host process. The checked-in compressed worker makes ordinary source builds work without a separate generation step. Maintainers regenerate it with sh tools/document/build.sh using the pinned Go toolchain and module versions. CI rejects source/asset drift; the image build independently rebuilds it. The release carries the parsers: operators do not build or publish them.

Tool contract and coverage

list_documents() returns opaque attachment IDs, names, media types and sizes from the current authorized conversation, bounded to the latest 100. It reports whether older entries were omitted. read_document(attachment_id, cursor?) returns the content SHA-256 revision, parser version, located text, extraction limitations, delivered coverage and an opaque continuation. With no cursor it starts at the beginning. Results are bounded to 16,000 Unicode code points and 200 blocks; blocks can span responses. Continuation is bound to attachment, revision and parser version, and every call reauthorizes and refetches. A changed/deleted source fails rather than silently splicing revisions. This release changes the parser version; old cursors must restart from the beginning.
  • PDF: physical page anchors. The bundled BSD-licensed Go PDF library reads embedded page text, not images, charts, form XObjects or annotations. Font decoding, layout and reading order can be imperfect; complex tables/columns are not faithfully reconstructed. PDF results always carry these limitations. Blank/scanned/unsupported pages are individually reported; entirely unreadable documents fail rather than claim a successful empty read.
  • DOCX: paragraph and table-row anchors, not invented page numbers. Main-body paragraphs/tables only; headers, footers, notes, images, nested tables, text boxes, numbering and tracked-change semantics are not fully represented.
  • TXT: UTF-8 (optional BOM), line anchors; binary/control-character content is rejected.
Extraction coverage is distinct from delivered coverage. Reaching the last response means the extracted text was delivered, not that images or omitted structures were read. Scans need rendering/OCR, not yet available. Unsupported, malformed, encrypted, empty and resource-exhausting inputs return an explicit failure without parser diagnostics/source bytes in logs.

Permissions and retention

The existing conversation/evidence rules remain unchanged:
  • Queries scope attachment IDs to agent perspective and conversation and require a source audience compatible with the current audience. IDs are not authority.
  • The owning Slack connector fetches using its credentials, after authorization, with size bounds and redirect/host restrictions. Credentials never enter WASI.
  • Source message evidence is accumulated before reading; derived replies and memories inherit it and the existing destination-audience recheck.
  • Document content is untrusted source material, never higher-priority instructions.
  • Mesh does not persist originals, extracted documents or page images. Authorized excerpts can occur in existing tool/run records under their retention policy.

Optional remote processing

Existing deployments explicitly setting MESH_DOCUMENT_IMAGE retain their remote processor override. This is advanced compatibility, not activation or normal setup. An override requires an immutable parser image and an execution backend that enforces no egress (currently Modal). Failure is explicit; an opted-in remote policy never silently falls back to local processing. With the setting absent, no execution-backend resolver or credential is consulted. tools/document/Dockerfile and its Python/Poppler tests are retained for this optional path. Its parser has different layout behavior from the bundled Go parser; both expose extraction limitations. The default path needs neither Python nor Poppler on the host.

Verification

  • go test ./internal/document/... runs real TXT/DOCX/PDF extraction through the embedded worker, pagination, partial/empty PDFs, malformed archives, output bounds, cancellation, WASI imports and hostile CPU/memory limit probes.
  • Turn tests exercise the native tools with the default processor and preserve authorization-before-fetch and source evidence checks. PostgreSQL tests cover cross-perspective, guessed-ID, wrong-conversation and wider-audience denial.
  • mesh document-check runs fixed DOCX/PDF/TXT fixtures through the bundled reader without database, provider credentials or environment configuration. Image CI invokes it in the actual release image with network disabled, read-only filesystem, all capabilities dropped and no-new-privileges. This check gates publishing.
  • A live Slack upload still requires a normally provisioned Slack agent with files:read; verify real DOCX/PDF uploads on the deployment before declaring the live incident resolved.
Telegram attachment ingestion, page rendering/OCR, private Drive/Docs adapters and extraction caching remain outside this release.

Conversation access failures

An unknown audience means Mesh could not establish a safe disclosure scope, not that the upload is absent or its format unsupported. Document tools return an explicit access-verification error before querying attachment metadata or fetching bytes. Reuploading or converting to PDF does not repair this condition. For Slack, inspect the Slack audience verification failed warning in the instance logs. Its sanitized reason identifies the failing API method and a recognized Slack error code, HTTP status, timeout, or incomplete-evidence error. Tokens, response bodies, channel identifiers, and membership lists are omitted. A missing_scope error calls for checking the installed app’s conversation-read permissions; not_in_channel calls for checking app membership. Neither is assumed from a generic failure. Public externally shared channels remain unverifiable by the current audience model and produce an unavailable warning. These diagnostics do not relax authorization or repair previously stored unknown source evidence. Verify a new conversation turn and upload after correcting the underlying cause; historical evidence must not be relabeled from current membership alone.