468edd8b22
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Agent work is issue-centered, and reviewers often need to inspect files, artifacts, and path references produced during that work. > - Before this branch, workspace-relative paths and artifact file references were not first-class inspectable objects in the board UI. > - Safe file viewing needs shared resource contracts, server-side workspace boundary checks, and UI that opens files without exposing arbitrary host paths. > - The workspace file viewer branch needed to stay as one active PR and be rebased onto current `paperclipai/paperclip:master` for review. > - This pull request adds the workspace file resource API, issue-page file viewer and browser, markdown file-reference links, and artifact file chips. > - The benefit is that board users can inspect relevant files from issue context while preserving workspace boundaries and auditability. ## Linked Issues or Issue Description No public GitHub issue exists for this branch. Internal Paperclip issues: `PAP-1953`, `PAP-10539`, `PAP-10733`. Problem / motivation: - Board users need to open workspace-relative files mentioned by agents or attached as work-product metadata without switching to a terminal. - The UI needs to support both direct file-path opening and workspace browsing/searching from an issue page. - The server must enforce company access, workspace boundaries, size limits, rate limits, and safe audit logging. Related PR: - Prior closed attempt: #4442 - Single active PR for this branch: #7681 ## What Changed - Added shared workspace file resource types, validators, and workspace-file `resourceRef` metadata validation for work products. - Added server routes/services for resolving, listing, and previewing workspace-relative files with access checks, scan caps, list-specific limits, and audit logging. - Added the issue file viewer provider, sheet, workspace browser, command-palette action, markdown workspace-file autolinks, and artifact file chips. - Updated issue workspace UI and stories/tests for file browsing and workspace file opening. - Rebased the branch onto current `paperclipai/paperclip:master` and updated the existing single PR branch. - Addressed current-head Greptile follow-ups by applying `offset` consistently across search/recent/changed file listings, restoring stopped-service port ownership checks before auto-port reuse, and stabilizing the workspace browser pagination test. ## Verification Current local verification after rebase to `public/master`: - `pnpm exec vitest run packages/shared/src/work-product.test.ts server/src/__tests__/file-resources.test.ts server/src/__tests__/instance-settings-routes.test.ts server/src/__tests__/instance-settings-service.test.ts server/src/__tests__/workspace-runtime.test.ts ui/src/components/FileViewerSheet.test.tsx ui/src/components/FileViewerSheet.copy.test.tsx ui/src/components/WorkspaceFileBrowser.test.tsx ui/src/components/WorkspaceFileMarkdownBody.test.tsx ui/src/context/FileViewerContext.test.ts ui/src/lib/remark-workspace-file-refs.test.ts ui/src/lib/workspace-file-parser.test.ts ui/src/components/IssueWorkspaceCard.test.tsx` - 13 files passed, 197 tests passed. - `pnpm -r --filter @paperclipai/shared --filter @paperclipai/server --filter @paperclipai/ui typecheck` - passed. - `pnpm exec vitest run ui/src/components/WorkspaceFileBrowser.test.tsx` - 1 file passed, 25 tests passed. - `pnpm exec vitest run server/src/__tests__/file-resources.test.ts server/src/__tests__/workspace-runtime.test.ts` - 2 files passed, 90 tests passed. - `pnpm -r --filter @paperclipai/server typecheck` - passed. - Confirmed branch is `0` behind and `46` ahead of current `public/master` after rebase and follow-up commits. - Confirmed the PR diff does not include `pnpm-lock.yaml`. - Confirmed the PR diff does not include `.github/workflows` changes. - Searched GitHub for duplicate or related workspace file viewer PRs/issues; #4442 is the prior closed attempt and this PR is the single active PR for the branch. - No screenshots were committed; the task explicitly asked not to add design screenshots or images unless they were part of the work. Current remote verification on head `a698a7bc10137baf7d25bd5722e1d6e0343387c1`: - Greptile Review - success, 64 files reviewed, 0 comments added, no unresolved Greptile review threads. - PR workflow `verify` - success. - Typecheck + Release Registry, General tests, workspace test shards, serialized server suites, Build, Canary Dry Run, e2e, Socket, and Snyk - success. - `security-review` - neutral, with output saying a draft advisory was filed for maintainer review and is not a merge block. - `commitperclip PR Review / review` - cancelled after the security gate detected flags and timed out while creating/reviewing the advisory. I reran it once and it cancelled the same way; no actionable code/test failure was exposed in the job logs. ## Risks - This is a broad UI/server feature PR, so review needs to pay attention to route authorization, workspace boundary handling, and markdown autolink false positives. - Workspace browsing intentionally caps list results and scan depth; very large workspaces may require users to refine search terms. - Remote workspace preview remains unavailable until remote file-access support is implemented. - The neutral commitperclip security-review advisory needs maintainer review, but the check output says it is not a merge block. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected - check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex, GPT-5 coding agent in a Paperclip/Codex local tool-use environment, medium reasoning, with shell/GitHub CLI tool use for branch inspection, verification, rebase, PR update, Greptile review, and CI inspection. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
142 lines
5.0 KiB
Markdown
142 lines
5.0 KiB
Markdown
# Agent Artifact Upload Workflow
|
|
|
|
Generated files that a board user or reviewer should inspect as deliverables
|
|
must be attached to the Paperclip issue before the agent chooses a final
|
|
disposition. A local workspace path is not enough, because cloud users and
|
|
reviewers often cannot access the agent's disk.
|
|
|
|
Use the helper bundled with the Paperclip skill from the repo root:
|
|
|
|
```sh
|
|
skills/paperclip/scripts/paperclip-upload-artifact.sh path/to/output.webm \
|
|
--title "Walkthrough render" \
|
|
--summary "Rendered walkthrough for review"
|
|
```
|
|
|
|
The helper uses the authenticated Paperclip API from the current heartbeat
|
|
environment:
|
|
|
|
- `PAPERCLIP_API_URL`
|
|
- `PAPERCLIP_API_KEY`
|
|
- `PAPERCLIP_COMPANY_ID`
|
|
- `PAPERCLIP_TASK_ID`
|
|
- `PAPERCLIP_RUN_ID`
|
|
|
|
It uploads the file to
|
|
`POST /api/companies/{companyId}/issues/{issueId}/attachments` and creates an
|
|
artifact work product on `POST /api/issues/{issueId}/work-products` by default.
|
|
The command prints issue-safe markdown links for the final task comment.
|
|
|
|
## Uploaded Artifacts vs Workspace Files
|
|
|
|
Use uploaded artifacts for deliverables: videos, PDFs, screenshots, archives,
|
|
reports, rendered HTML, or any file the board should inspect without needing the
|
|
agent's checkout. Attachment-backed artifact work products set `type` to
|
|
`artifact` and `provider` to `paperclip`, with metadata canonicalized from the
|
|
uploaded `attachmentId`.
|
|
|
|
Use `workspace_file` metadata only for important files that intentionally remain
|
|
in a project or execution workspace, such as source files, committed markdown
|
|
plans, or generated files whose meaning depends on the checkout. Workspace-only
|
|
references are useful signposts, but they are not durable uploads.
|
|
|
|
Expected work product metadata shape:
|
|
|
|
```json
|
|
{
|
|
"resourceRef": {
|
|
"kind": "workspace_file",
|
|
"issueId": "<issue-id>",
|
|
"workspaceKind": "execution_workspace",
|
|
"workspaceId": "<execution-workspace-id>",
|
|
"relativePath": "doc/plans/example.md",
|
|
"line": 1,
|
|
"column": 1,
|
|
"displayPath": "doc/plans/example.md:1:1"
|
|
}
|
|
}
|
|
```
|
|
|
|
`workspaceKind` is `execution_workspace` or `project_workspace`. `line` and
|
|
`column` are optional. `relativePath` must be relative to that workspace root;
|
|
do not store host-local absolute paths as workspace references.
|
|
|
|
Workspace file links resolve only inside registered Paperclip workspaces. The
|
|
default target is the current issue's execution workspace first, then its
|
|
project workspace. A link may target another same-company project workspace only
|
|
when it carries both that `projectId` and `workspaceId`. Paperclip does not
|
|
resolve arbitrary machine-wide filesystem paths, absolute host paths, home
|
|
paths, or relative paths that escape the selected workspace.
|
|
|
|
## Completion Pattern
|
|
|
|
When a task produces a user-inspectable deliverable file:
|
|
|
|
1. Generate and verify the file locally.
|
|
2. Upload it with `skills/paperclip/scripts/paperclip-upload-artifact.sh`.
|
|
3. Keep the artifact work product unless the file is incidental; pass
|
|
`--no-work-product` only for supporting files that should not be promoted.
|
|
4. Link the printed attachment URL in the final issue comment.
|
|
5. Then set the final issue status.
|
|
|
|
Final comments should name and link the uploaded artifact or work product, not
|
|
just the local filesystem path. For workspace-only files, include the work
|
|
product title and recorded relative path. Local paths can be included as
|
|
diagnostic context, but they cannot be the only access path. Browse/search is a
|
|
fallback for recovering workspace files when the issue link or chip is not
|
|
available, not the preferred way to deliver files to users.
|
|
|
|
## Video Examples
|
|
|
|
Upload an `.mp4` render:
|
|
|
|
```sh
|
|
skills/paperclip/scripts/paperclip-upload-artifact.sh dist/demo.mp4 \
|
|
--title "Demo video render" \
|
|
--summary "MP4 render for board review"
|
|
```
|
|
|
|
Upload a `.webm` render:
|
|
|
|
```sh
|
|
skills/paperclip/scripts/paperclip-upload-artifact.sh out/walkthrough.webm \
|
|
--title "Walkthrough video" \
|
|
--summary "WebM walkthrough render"
|
|
```
|
|
|
|
The helper detects `.mp4`, `.webm`, and `.mov` content types. If a renderer uses
|
|
an unusual extension, pass the MIME type explicitly:
|
|
|
|
```sh
|
|
skills/paperclip/scripts/paperclip-upload-artifact.sh render.bin \
|
|
--title "Demo video render" \
|
|
--content-type video/mp4
|
|
```
|
|
|
|
## Direct API Pattern
|
|
|
|
If the helper is unavailable, use the same API shape:
|
|
|
|
```sh
|
|
curl -sS -X POST \
|
|
"$PAPERCLIP_API_URL/api/companies/$PAPERCLIP_COMPANY_ID/issues/$PAPERCLIP_TASK_ID/attachments" \
|
|
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
|
|
-H "X-Paperclip-Run-Id: $PAPERCLIP_RUN_ID" \
|
|
-F 'file=@"dist/demo.mp4";type=video/mp4'
|
|
```
|
|
|
|
Then create a work product when the uploaded file is the deliverable:
|
|
|
|
```sh
|
|
curl -sS -X POST \
|
|
"$PAPERCLIP_API_URL/api/issues/$PAPERCLIP_TASK_ID/work-products" \
|
|
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
|
|
-H "X-Paperclip-Run-Id: $PAPERCLIP_RUN_ID" \
|
|
-H "Content-Type: application/json" \
|
|
--data-binary @artifact-work-product.json
|
|
```
|
|
|
|
Use `type: "artifact"`, `provider: "paperclip"`, and metadata containing the
|
|
uploaded `attachmentId`. The server canonicalizes `contentType`, `byteSize`,
|
|
`contentPath`, `openPath`, `downloadPath`, and `originalFilename`.
|