Repository navigation
Open
Labels
area:aiAI-native — agent / tool / skill metadata, and the MCP surface an agent drivesAI-native — agent / tool / skill metadata, and the MCP surface an agent drivesarea:filesFiles — upload, download, signed URLs, access derived from the parent recordFiles — upload, download, signed URLs, access derived from the parent recorddomain:serverDomain lane — seat card indexed by label:pm:seatDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestNew feature or requestpm:queueReady for the PM dispatch loopReady for the PM dispatch looppriority:p1High: required for production / M2High: required for production / M2
Description
coordinator#1 · hotlong · session_6eb9ec2e0e3f410b91239dab7a337b9e
Filing gate: ③ a task on the maintainer's word. Coordinator session, 2026-11-06: after reviewing screenshots of an MCP client (Claude app) working against a hosted environment, the maintainer said 「这些问题都需要立卡处理」, then 「你只需要立卡,不需要派发」.
Reader: domain:server (packages/mcp, with packages/services/service-storage). Cloud's half (storage quota, the bucket) follows on objectstack-ai/cloud if the design needs it. Suggested priority p1. Triage decides.
Dedupe:
- objectstack
MCP attachment,file field MCP: open hits are QA runs, Implement soft delete (recycle bin):enable.trash/softDeleteare spec-only with zero runtime readers #3146 (recycle bin), skills(objectstack-data): teach a field group's visibleWhen and requiresFeature in examples-objects.md #30812, [Decision] A package can be disabled while an enabled package's validation rule reads one of its extension fields, and then every write to that object is refused #30379. None is file access over MCP. - cloud
MCP attachment: open hits unrelated.
维护者速读
两个真实场景:一是拍一张发票,让 AI 建报销单并把发票图片挂上去;二是系统里存着规章制度的附件,让 AI 下载下来分析。现在 MCP 两样都做不到:工具里没有任何读写文件的。AI 能看懂照片、把字段填进报销单,但挂不上原图;存成附件的 PDF 也读不到。
What is there today (objectstack origin/main)
- The MCP tools in
packages/mcp/src/mcp-http-tools.tsread and write records and run actions. None touches storage: no upload, download or presign anywhere inpackages/mcp/src. - Records carry
Field.file/Field.image(spec/src/data/field.zod.ts:3473-3474) and attachments live inservice-storage(attachment-lifecycle.ts). - An AI client sees an image the user attaches in its own chat, but it has no bytes to send. The MCP protocol has no standard client-to-server file transfer.
Ask
- Read a file. A tool that, for an attachment or a file field the caller can see, returns its text for analysis (PDF and Word extracted to text; images as an image content block where the protocol allows), plus a short-lived download link for a person. Access follows the record: no record access, no file. A size cap, named in the answer.
- Attach a file through a one-time upload link. A tool that, for a record the caller may edit, returns a short-lived, single-use link bound to that record and field. The person opens it on their phone and picks the photo, and it lands as the record's attachment. The link expires in minutes and uploads count toward the storage quota.
- Direct upload through the protocol when clients can send file content; out of scope until then, noted so the design leaves room.
Acceptance
- Tests pin access following the record, the size cap, the link's single use and expiry, and the binding to one record and field.
- On a hosted environment: an MCP client reads a PDF attachment's text and summarises it. A photographed invoice ends up attached to the expense record it created, through the link.
🤖 Generated with Claude Code
Metadata
Metadata
Assignees
Labels
area:aiAI-native — agent / tool / skill metadata, and the MCP surface an agent drivesAI-native — agent / tool / skill metadata, and the MCP surface an agent drivesarea:filesFiles — upload, download, signed URLs, access derived from the parent recordFiles — upload, download, signed URLs, access derived from the parent recorddomain:serverDomain lane — seat card indexed by label:pm:seatDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestNew feature or requestpm:queueReady for the PM dispatch loopReady for the PM dispatch looppriority:p1High: required for production / M2High: required for production / M2
Activity
objectstack-fleet commentedon Nov 6, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p1 kept ·
domain:server· re-queued · 2026-11-06T12:44Z⛔ Not a claim.
packages/mcpplusservice-storagesurface.pm:*state, so no seat could see it. That was a triage sweep miss, fixed this round.Generated by Claude Code
objectstack-fleet commentedon Nov 6, 2026
domain:server#4 · os-elon-musk · session_016WV4czvZykUqhYxYXSSDt4
Claim: PM loop round 1 · 2026-11-06T12:50Z
Session:
session_016WV4czvZykUqhYxYXSSDt4Account:
os-elon-musk(the seat's linked user asGET /useranswers it; the card's assignee)Branch: the card thread's designated
claude/project-thread-*branch, re-posted in a whole claim once the thread reports itWorktree:
objectstack-issue-30892Domain:
domain:serverSeat:
domain:server#4File surface: two new MCP tools and their wiring (
packages/mcp/src/**: tool registration, the data-bridge members, and the MCP-servedskill-md.tslines), the runtime half of the MCP bridge where it reads attachments (packages/runtime/src/domains/mcp.ts), the storage service's existing read, presign and attach paths (packages/services/service-storage/src/**, only to call or expose an existing door, plus one single-use upload-link record if none exists), their tests and dogfood;content/docs/ai/connect-mcp.mdx; one root.changeset/file. ⛔packages/spec/**: if a published key or schema is needed, the dev stops after measuring and the seat files thedomain:specsub-card first. ⛔ui/**,skills/**(stop on breach; explain in the report)Container & model:
L,mode:thread,model: default,effort: xhigh(p1)Clause-②: yes (widening) (provisional: two new tools on the published MCP surface; the dev measures and reports the arm)
Metadata-protocol: none (provisional;
addedonly through the spec sub-card)Responsibility: n/a — new capability, not a regression
Thread-read: 6685125943
Premise: card body (maintainer 「这些问题都需要立卡处理」) and triage 6685125943 (p1 kept). Two tools follow.
Direct protocol upload is out of scope. Cloud's half (quota, bucket) goes to objectstack-ai/cloud only if the design needs it.
Serial constraints cleared: the dev re-reads open PRs touching
packages/mcp/src/mcp-http-tools.tsat branch start (PR feat(mcp)!: delete_record refuses a call without confirm: true #30861 and PR fix(platform-objects)!: platform-admin actions declare their gate, read by MCP list_actions and both action doors #30849 are open on it, awaiting the maintainer's word; rebase onto whichever lands first)Contract review owed (a widening of the public MCP surface) before the queue.
objectstack-fleet commentedon Nov 6, 2026
domain:server#4 · os-elon-musk · session_016WV4czvZykUqhYxYXSSDt4
Claim: PM loop round 1 (re-posted whole with the branch) · 2026-11-06T12:56Z
Session:
session_016WV4czvZykUqhYxYXSSDt4Account:
os-elon-musk(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/project-thread-s2vcdkDev session:
session_016WV4cyqd3A7fbCWrqM3KCz(the card thread that implements; this seat lands)Worktree:
objectstack-issue-30892Domain:
domain:serverSeat:
domain:server#4File surface: two new MCP tools and their wiring (
packages/mcp/src/**: tool registration, the data-bridge members, and the MCP-servedskill-md.tslines), the runtime half of the MCP bridge where it reads attachments (packages/runtime/src/domains/mcp.ts), the storage service's existing read, presign and attach paths (packages/services/service-storage/src/**, only to call or expose an existing door, plus one single-use upload-link record if none exists), their tests and dogfood;content/docs/ai/connect-mcp.mdx; one root.changeset/file. ⛔packages/spec/**: if a published key or schema is needed, the dev stops after measuring and the seat files thedomain:specsub-card first. ⛔ui/**,skills/**(stop on breach; explain in the report)Container & model:
L,mode:thread,model: default,effort: xhigh(p1)Clause-②: yes (widening) (provisional: two new tools on the published MCP surface; the dev measures and reports the arm)
Metadata-protocol: none (provisional;
addedonly through the spec sub-card)Responsibility: n/a — new capability, not a regression
Thread-read: 6685125943
Premise: card body (maintainer 「这些问题都需要立卡处理」) and triage 6685125943 (p1 kept). Two tools follow.
Direct protocol upload is out of scope. Cloud's half (quota, bucket) goes to objectstack-ai/cloud only if the design needs it.
Serial constraints cleared: the dev re-reads open PRs touching
packages/mcp/src/mcp-http-tools.tsat branch start (PR feat(mcp)!: delete_record refuses a call without confirm: true #30861 and PR fix(platform-objects)!: platform-admin actions declare their gate, read by MCP list_actions and both action doors #30849 are open on it, awaiting the maintainer's word; rebase onto whichever lands first)Contract review owed (a widening of the public MCP surface) before the queue.
test(mcp,storage): pin read_file and create_upload_link on a booted s…
docs(permissions): count the record-file verbs in the tenant-audit an…
test(dogfood): the MCP context-thread pin admits the bridge's per-req…
objectstack-fleet commentedon Nov 6, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
To: domain:server#4
Request: progress · #30892 · idle since 2026-11-06T12:56Z
Generated by Claude Code
fix(storage): an upload link works only for the user it was minted fo…
objectstack-fleet commentedon Nov 6, 2026
domain:server#4 · os-elon-musk · session_016WV4czvZykUqhYxYXSSDt4
Handoff to
domain:server#2· 2026-11-06T17:02Z · server seat 4 is signing off on the maintainer's word, and the contract review is left to the next seat. The maintainer's word for this card: server seat 2 takes it over.State:
claude/project-thread-s2vcdk, built by card thread sessionsession_016WV4cyqd3A7fbCWrqM3KCz. Option B (the upload link needs the minting user's session) is at04ff76bc: 111/111 derived gates, full dogfood 426 files 0 failed. The dev is pushing it now and opening a draft PR withFixes #30892; the PR body states what is still open./mnt/project-files/server-lane-seat4/30892/section1-measurements.md(project files). Seat rulings: D1unpdf@1.9.1pinned exact (2.x needs node 24), a dependency of@objectstack/mcponly, dynamic import. D2: the link record is the pendingsys_filerow. D3: judged at mint and re-resolved as the minting user at upload.Owed by the next seat:
Clause-②: yes (widening): two new MCP tools and two new storage routes). Its security face covers the token entropy, hash at rest, single use, expiry, and one same-shaped answer for a used, expired or unknown link. Then decide whether to notify security#1.check-governed-mergeson the final file list.The claim (6685332126) is released with this note: the assignee is removed and the card returns to
pm:queuefor server seat 2 to claim.Merge origin/main into claude/project-thread-s2vcdk (#30892)
test(dogfood): the upload-link PUT sends a Uint8Array body, so the do…
test(runtime): the record-file bridge test pays the metadata load dur…
objectstack-fleet commentedon Nov 6, 2026
domain:server#2 · os-tesla · session_01L9qibyvxbrLP4jm4PargoH
Ruling · 2026-11-06T17:40Z · how the shared delete link is used (seat 4 brief 6690566522)
The maintainer ruled in the server seat 2 thread 2026-11-06T17:36Z, option B: the link works only for a signed-in user, as PR #31009 builds it. Option A (a bearer link usable without sign-in, which would need an ADR-0138 amendment) is not taken. PR #31009 now owes the seat's widening contract review (token entropy, hash at rest, single use, expiry, one same-shaped answer); the seat runs it and lands the PR on PASS.
objectstack-fleet commentedon Nov 6, 2026
domain:server#4 · os-elon-musk · session_016WV4cyqd3A7fbCWrqM3KCz
os-dev-report
{ "status": "done", "branch": "claude/project-thread-s2vcdk", "pr": "https://github.com/objectstack-ai/objectstack/pull/31009", "session": "session_016WV4cyqd3A7fbCWrqM3KCz", "premise_still_valid": true, "summary": "Two MCP tools: read_file (a record's file field or attachment, as extracted text for PDF/.docx/text, an image block, a short-lived download link, size and the 10 MiB cap; access follows the record with get_record's and the download door's own codes) and create_upload_link (a 600 s single-use link bound to one record and field or the attachments list, minted after the record's edit door; the upload lands as the record's file through engine.update / attachFileAs as the minting user, re-resolved). Built as option B: the link works only for the minting user, signed in (no session 401 AUTH_REQUIRED, another user the same 404, nothing spent), so the ADR-0138 D2 anonymous-door sweep holds unchanged. Elon's A/B sign-in choice is still open, and landing waits on it: A = bearer link plus an ADR-0138 amendment and a revert of 04ff76bc. Server seat 4 signed off; the card is handed to server seat 2 (handoff 6690566522), the claim is released, the PR has no assignee, and the Clause-② (widening) contract review is owed to that seat.", "tests": "Head 67847d9c. service-storage 74 files 1388/1388; mcp 58 files 711/711; runtime src/mcp-record-file-bridge.test.ts 5/5; tsc --noEmit on service-storage, mcp, runtime and dogfood exit 0; dogfood showcase-mcp-record-files + anonymous-door-sweep + authz-conformance 3 files 93/93. New suites: record-file-access.integration.test.ts 21, mcp-file-tools.test.ts 21, mcp-record-file-bridge.test.ts 5, showcase-mcp-record-files.dogfood.test.ts. Ablations (service-storage integration): spend guard `if (!spent)` -> `if (spent < 0)` turned 'of two concurrent uses exactly one lands' red (1 failed / 19 then); removing `deadline <= this.now()` turned the expiry test red; both restored, blobs equal HEAD.", "gates": "dispatch-gates --commands derives 111 on the merge head (same set as 04ff76bc). Run over the merged tree while two test-only commits (f30868c7, 67847d9c) landed: 111/111 exit 0; --ran: 111 derived, 111 run, 0 NOT-MEASURED. Two reruns, both prerequisites, not findings: check:type-check-debt exited 3 (scenarios dts build lacked playwright-core because pnpm install had not run after the main merge; after install + rebuild it exits 0), and on 04ff76bc check-comment-mask-corpus hit ENOENT on a dogfood temp bundle (rerun exit 0). Not in the derivation: @objectstack/dogfood#typecheck (CI 'Type Check · workspace' caught TS2322 on c5fe7df9, fixed f30868c7) and check:test-source-alias red after the merge (fixed 67847d9c). CI on 67847d9c: 66 check-runs, 59 success and 7 skipped by their own filters, 0 failed (reds on c5fe7df9 and f30868c7 were the two fixes above plus aggregators of shards cancelled by the next push).", "dogfood_battery": "n/a by rule (no `!` in the title, Clause-② widening), run anyway: merge tree (c5fe7df9 + f30868c7) · os-verify-lock: VERDICT command-exit 0 · Test Files 429 passed + 3 skipped / 432 · Tests 3573 passed + 41 skipped / 3614 · 0 failed. On 04ff76bc: 426 + 3 skipped / 429, 0 failed.", "mcp_calls": "21, all GitHub reads: issue_read x6, list_pull_requests x4, pull_request_read x8, get_job_logs x3. No MCP write. (Two check-run reads also went through gh api.)", "api_writes": "2 relay writes: pr_create (POST /repos/objectstack-ai/objectstack/pulls, draft; read-back 22074 bytes identical) and this os-dev-report comment (POST /repos/objectstack-ai/objectstack/issues/30892/comments). Plus 5 git pushes (75bc8cfa..67847d9c), which are not REST writes.", "open_questions": [ { "question": "Does the upload link need the minting user to be signed in?", "options": [ "A: bearer link, so a phone that is not signed in can upload; needs an ADR-0138 amendment admitting the two routes as an outside family, then revert 04ff76bc", "B: only the minting user, signed in (built; sweep unchanged)" ], "recommendation": "B, because it keeps the anonymous-door sweep closed with no ADR change, and a forwarded or leaked link works for nobody else; the cost is signing in on the phone first." } ], "security_findings": "none", "out_of_scope_findings": [ "carrier: none · noted, not filed — dispatch-gates --commands does not derive @objectstack/dogfood#typecheck, so a dogfood test type error shows only in CI 'Type Check · workspace'.", "carrier: none · noted in the PR's Acceptance notes — an ADR-0069 hold on the minting user is not re-checked at upload; the link path follows the plugin basePath; no byte quota exists in the open tree (cloud's half)." ] }Generated by Claude Code