Skip to content

feat(commonly): commonly_attach_file extension tool + path-policy plugin-sdk export#2

Merged
samxu01 merged 2 commits intorebase-2026.3.29from
feat/commonly-attach-file
May 4, 2026
Merged

feat(commonly): commonly_attach_file extension tool + path-policy plugin-sdk export#2
samxu01 merged 2 commits intorebase-2026.3.29from
feat/commonly-attach-file

Conversation

@samxu01
Copy link
Copy Markdown

@samxu01 samxu01 commented May 4, 2026

Summary

Implements the kernel-layer file-delivery verb described in ADR-013 (Team-Commonly/commonly#287). Agents call commonly_attach_file with a workspace-relative path; the tool reads the file, uploads it via the agent runtime endpoint, and (optionally) posts a chat message containing the [[upload:...]] directive that the v2 inspector renders as a clickable preview pill.

This is the first of the ADR-013 implementation PRs — Phase 0b in the ADR's phasing. Phase 1 (default skill bundles for dev presets) and the gateway Dockerfile toolchain (OfficeCLI + pandoc + markitdown) follow in separate PRs.

Changes

Three files, all additive (177 insertions, 0 deletions):

1. extensions/commonly/src/client.ts — new uploadFile() method

Multipart/form-data POST to /api/agents/runtime/pods/:podId/uploads using the runtime token. Returns {_id, fileName, originalName, size, kind} which the tool embeds in the [[upload:...]] directive.

2. extensions/commonly/src/tools.ts — new commonly_attach_file tool

commonly_attach_file({
  podId: string,           // required
  filePath: string,        // workspace-relative, must not escape /workspace/<accountId>/
  message?: string,        // optional caption — posts message with directive appended
  replyToId?: string,      // optional reply threading
})
   { ok, file: {_id, fileName, originalName, size, kind}, message? | directive }

Validates the path via toRelativeWorkspacePath, reads up to 25 MB, detects MIME from extension (server validates against the ADR-002 allowlist), uploads, and either posts a chat message or returns metadata for the caller to compose its own.

3. src/plugin-sdk/index.ts — exports path-policy helpers

`toRelativeWorkspacePath` / `toRelativeSandboxPath` / `resolvePathFromInput` from `src/agents/path-policy.js`. These existed in core but weren't visible to plugins. Phase 0a (iii) of ADR-013 verified the helpers are high quality (rejects `..`, resolves symlinks, cross-platform); they just needed the export.

Why kernel-layer

`commonly_attach_file` is runtime-agnostic by construction. Any runtime that produces a file in the agent workspace — gateway-resident agents, ADR-005 wrapper agents, future webhook agents — calls the tool with the same shape and the file lands in chat.

Test plan

This is a new tool with no existing tests. After merge:

  • commonly bumps the submodule pointer
  • Deploy Dev rebuilds the gateway image
  • Hand-test: dev agent drops a fixture PDF in workspace, calls `commonly_attach_file`, file appears in chat with preview pill
  • Hand-test: path-traversal attempt (`../../etc/passwd`) is rejected
  • Hand-test: file >25MB is rejected

Unit-level vitest coverage is a follow-up — getting the surface in front of agents on dev first.

Companion

ADR-013 #287 (merged) — design doc.
Phase 0a findings #291 — closes Q1/11/12/13.

🤖 Generated with Claude Code

samxu01 and others added 2 commits May 3, 2026 19:57
…gin-sdk export

Adds the kernel-layer file-delivery verb described in ADR-013 (Team-Commonly/commonly).
Agents call commonly_attach_file with a workspace-relative path; the tool reads the
file, uploads it via the agent runtime endpoint, and (optionally) posts a chat
message containing the [[upload:...]] directive that the v2 inspector renders as
a clickable preview pill.

Three changes:

1. extensions/commonly/src/client.ts — new uploadFile() method that posts
   multipart/form-data to /api/agents/runtime/pods/:podId/uploads using the
   runtime token. Returns {_id, fileName, originalName, size, kind} which the
   tool embeds in the directive.

2. extensions/commonly/src/tools.ts — new commonly_attach_file tool. Validates
   the path stays inside /workspace/<accountId>/ via toRelativeWorkspacePath,
   reads up to 25 MB, detects MIME from extension (server validates the
   allowlist), uploads, and either posts a message with the directive or
   returns metadata for the caller to compose its own.

3. src/plugin-sdk/index.ts — exports toRelativeWorkspacePath /
   toRelativeSandboxPath / resolvePathFromInput from src/agents/path-policy.
   Previously these were available in core but not visible to plugins.

Runtime-agnostic by construction: any runtime that produces a file in the
agent workspace can deliver it to chat through this verb. No skill or
runtime mechanism is hard-coded.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds OPENCLAW_INSTALL_DOC_TOOLCHAIN gated install of the document-generation
toolchain that backs commonly_attach_file's deliverable flow per ADR-013
(Team-Commonly/commonly#287). Same opt-in pattern as the existing
OPENCLAW_INSTALL_GH_CLI / OPENCLAW_INSTALL_DOCKER_CLI / OPENCLAW_INSTALL_BROWSER
flags so upstream openclaw's default image stays unchanged.

What gets installed (~170 MB total when enabled):

  * OfficeCLI (iOfficeAI, Apache-2.0): pinned static binary for DOCX/XLSX/PPTX
    create+edit+validate. Pinned via OPENCLAW_OFFICECLI_VERSION (default
    1.0.70). Downloads platform-appropriate asset, verifies SHA256 against the
    release's published SHA256SUMS artifact, installs to /usr/local/bin/officecli.

  * pandoc + texlive-xetex + texlive-fonts-recommended: markdown → PDF
    (LaTeX engine), markdown → simple DOCX fallback.

  * poppler-utils: pdftoppm/pdftotext for PDF-skill workflows.

  * python3 + pip + markitdown + pypdf: parse direction — agent reads
    user-attached PDFs/DOCX/XLSX and converts to markdown for input.

Build-time self-test runs `officecli --version`, `pandoc --version`, and a
`python3 -c "import markitdown, pypdf"` check so a regression surfaces at
build time rather than as "command not found" at agent runtime.

Architecture-aware: x86_64 → officecli-linux-x64; aarch64 → officecli-linux-arm64;
other arches fail the build (rather than silently skipping).

Commonly's deploy invocation enables this with --build-arg OPENCLAW_INSTALL_DOC_TOOLCHAIN=1.
Upstream builds unaffected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@samxu01 samxu01 changed the base branch from main to rebase-2026.3.29 May 4, 2026 03:44
@samxu01 samxu01 merged commit 4bf74df into rebase-2026.3.29 May 4, 2026
1 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant