Repository navigation
content(blog): agent-operable apps — every object and action an MCP tool under the user's permissions (post 4, slot 2026-10-20) - #237
Open
objectstack-fleet[bot] wants to merge 4 commits into
Conversation
…ool under the user's permissions (slot 2026-10-20) Post 4 of the positioning wave (#230). New post in en, zh-Hans, zh-Hant (generated), ja and ko, with two covers and two diagrams in English and Chinese. The proof artifact is a real run on the published 17.7.0 packages: a scaffolded expense desk, two users with their own API keys, the same twelve tools, one action refused for the submitter and permitted for the approver, and the action absent until its author opts it in. Also in this PR: ontology-mcp-agent-tools gets updated: 2026-10-20, its closing aligned with the README's renamed "Agents are the first users" section and the README agent path, and one sentence that called the ontology a semantic layer corrected. Slug and date unchanged. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
The "not attempted" / "未尝试" cells used #7c8498 on white, 3.74:1 in the browser check; #5b6478, the small-text grey the rest of the diagram uses, reads 6.2:1. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
The positioning wave's slots slipped by one week: post 1 missed its Thu 2026-10-08 slot and moves to Thu 2026-10-15, post 2 to Tue 2026-10-20 and post 3 to Thu 2026-10-22. Under the publishing cadence (two slots a week, one post per slot, an agent's `date` is its planned slot, never two posts on one day) post 4 can no longer hold Tue 2026-10-20, which post 2 now takes, so it moves to the next Tuesday. The post is unpublished, so its first-publication `date` may still change: `date: 2026-10-20` becomes `date: 2026-10-27` in the en, ja, ko and zh-Hans files, and zh-Hant is regenerated with `pnpm gen:zh-hant`. The back-linked ontology-mcp-agent-tools post gets its revision on the day the link goes live, so its `updated` moves from 2026-10-20T10:00:00+08:00 to 2026-10-27T10:00:00+08:00. No other changes. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
This was referenced Oct 15, 2026
Draft
…y cadence, #267) Ruling B on #267 switches on now that seven approved posts are queued, and the seat starts the daily run on 2026-10-18. Post 4 is unpublished, so its date moves from Tue 2026-10-27 to Tue 2026-10-20 in every authored locale (en, ja, ko, zh-Hans), and the updated stamp it writes on the back-linked published post ontology-mcp-agent-tools (en) moves with it. zh-Hant is regenerated with pnpm gen:zh-hant. No published post's date changes. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #230
Post 4 of the positioning wave (#209), slot Tuesday 2026-10-27. Merge on the slot day and no earlier: www AGENTS.md says "merge time is publish time".
Re-slot. The post was slotted for Tue 10-20. The wave slipped one week when post 1 missed 10-08 and landed on 10-15 as #212, so post 4 moved to the next free slot. Commit
7f1c50bmovesdateto 2026-10-27 in all five locale files, and moves the sibling'supdatedto2026-10-27T10:00:00+08:00. 6 lines change. Gates on that commit all exit 0: content:lint, check, build (893 pages, tree clean) and seo:smoke.Branch. This branch holds three commits replayed onto
main@51147d6. The replay is patch-equal tolin/post-base..lin/issue-230, with byte-identical diffs. Head813f3de.What this PR adds
New post
content/blog/agent-operable-apps-mcp-tools-user-permissions/in en, zh-Hans, zh-Hant (generated bypnpm gen:zh-hant), ja and ko,date: 2026-10-27, noupdated,topic: ai-agents,audience: developer. Title as ruled: Agent-Operable Apps: When Every Object and Action Is an MCP Tool Under the User's Permissions. Promise: Agent-operable.npm create objectstack@latest expense-desk, Create ObjectStack v17.7.0, published packages, Node 22), one object, oneoperation: 'update'action gated by a capability, two permission sets, two users created through the documented admin route, each holding an API key minted on their own account, a JSON-RPC probe against/api/v1/mcp. Output quoted trimmed, not rewritten.T4_STANDALONE+ E1 verbatim fromsrc/lib/positioning.ts, per locale.npm create objectstack@latest, the agent,npx os dev --ui, then the README's ownclaude mcp addline).os startappears 0 times. No token figures. No competitor claims.cover-en.svg/cover.svg(1200×675),same-list-two-answers-en.svg/.svg(1200×700),action-gate-en.svg/.svg(1200×560). ja and ko use the English set, zh-Hans/zh-Hant the Chinese pair. Root tag closes within the first 460–750 bytes of each file, inside Astro's 1 KB probe window.Updated post
content/blog/ontology-mcp-agent-tools/index.mdx(en only; the post has no other locale):updated: 2026-10-27T10:00:00+08:00; slug anddateunchanged.claude mcp addline.Claims and their sources
/api/v1/mcp, on by default; "under the same permissions and RLS as a human"; each deployment is its own OAuth server; API key for headless; objects exposed automatically, actions opt in withai: { exposed: true }README.md:148-164at8caa131e, quoted whole as a blockquoteT4_STANDALONE), E1src/lib/positioning.tsdata:read/data:write/actions:executenarrow the toolset; API-key and session callers get the full set; the "fixed ~10-tool spine with the object name as a parameter"; twelve tools;sys_*blocked fail-closed; "default exposure policy (v1)", "not a ceiling", #3167; stdio advice "mint the key on a user with exactly the access it should have"; client-side confirmation;POST /api/v1/keys; the anonymous probe returns 401content/docs/ai/connect-mcp.mdxat8caa131eai.exposedfail-closed,requiredPermissions, record under RLS, body runs with the app's authority and is audit-logged); "Action bodies run as trusted code"; "the boundary is therefore at invoke time, not inside the body"; "ai.exposed is the security decision";ai.descriptionof at least 40 characterscontent/docs/ai/actions-as-tools.mdxat8caa131erequiredPermissionsis a dual-surface gate; the REST route answers 403content/docs/ui/actions.mdxPOST /api/v1/auth/admin/create-user,set-user-password; grants assys_user_permission_setrowscontent/docs/permissions/authentication.mdx,permissions/permission-sets.mdx--compile,os devbehaviourcontent/docs/deployment/cli.mdxtextcode blockscratchpad/issue-230/proof/*.log,server*.log,validate*.log,scaffold.log)Claims the post explicitly marks as the docs' and not measured: the audit-log step (5) and the OAuth-scope narrowing of the tool list (the run used API keys).
The run, in order (what the transcript actually did)
npm create objectstack@latest expense-desk(an earlieragent-deskscaffold was discarded for the name).npm run validate: 49 rules, passed, one advisory about owner-only read for the submitter set (quoted in the post).npx objectstack dev --no-watch -p 3230, first boot, noaiblock. Anonymous probe 401 withwww-authenticatenaming the deployment's/.well-known/oauth-protected-resource; that document names/api/v1/authas the authorization server with scopesdata:read data:write actions:execute offline_access.SELF_REGISTRATION_CLOSED, postureinvite_only); Ada and Sam created viaadmin/create-user, passwords set without the forced change,expense_desk_approvergranted to Ada andexpense_desk_submitterto Sam assys_user_permission_setrows; each user minted anosk_key viaPOST /api/v1/keys.initialize(serverInfo objectstack 17.7.0),tools/list(12),list_objects(2),list_actions→[].aiblock added, validate passed, restart without--compile: the runtime warned the artifact was stale and served the old one;run_actionanswered "is not exposed to AI — the app author must opt it in…" for both users. Recorded as what happened; the post's "before the opt-in" block uses the clean ablation in step 7, whose text is identical.--compile(exposedpresent indist/objectstack.json): Samcreate_record→ id9vBXoTWICx4MQupC; Sam/Adaquery_records→ 1 row each; Adalist_actions→approve_claim; Samlist_actions→[]; Samrun_action→ "requires capability [approve_claims] — caller is missing [approve_claims]"; Adarun_action→ ok,status: "approved",updated_byAda,owner_idSam; Samdelete_record→ "You do not have permission to perform this action…"; Samget_record→ his record, approved. A refused call is HTTP 200 withisError: true(checked with-w %{http_code}).aiblock removed (grep count 0), restart with--compile(exposedcount 0 in dist) → Adalist_actions[], Adarun_action"not exposed"; block restored (count 1), restart with--compile(count 2) → Adalist_actionslistsapprove_claim. Server stopped by PID afterwards; no process of this run left.Gates, on
b567417(all throughscripts/pm/os-verify-lock.sh, slotwww-230,VERDICT command-exit 0, held 121 s, waited 0 s, shared-box seconds)pnpm content:lint✓ content lint passed (352 files, 44 glossary terms checked)pnpm content:lint --publishedpnpm checkResult (152 files): 0 errors, 0 warnings, 0 hintspnpm build✓ zh-Hant: generated 48, kept 0 hand-maintained·svg-text-fit: OK (124 SVGs, 2722 text boxes…)·[build] 893 page(s) built in 72.33s·✓ content lint --dist passed (491 built blog pages checked)· CJK line breaks, quotation marks and links passed · tree clean afterwardspnpm seo:smokeSEO smoke test passed (883 HTML pages checked; 582 sitemap URLs against 301 noindexed pages; 5526 canonical/hreflang annotations; 16704 prose blocks language-checked; 94702 internal links redirect-checked)pnpm svg:lintsvg-text-fit: OK — … (124 SVGs, 2722 text boxes, 185 filtered elements, tolerance 2px, 1 allowlisted)Advisories, verbatim (all expected for a slot-day post with a ruled title):
Date is in the future: Tue Oct 20 2026 …×5 (now Oct 27 after the re-slot);Title is 93 columns wide (93 chars); search results show about 60, so the end is cut(en; zh-Hans 63, zh-Hant 65, ja 111, ko 78);Description is 207 columns wide (207 chars); search results show about 160…(en; zh-Hans 161, zh-Hant 165, ja 225, ko 204 — all ≤ 230 chars);content/blog/ontology-mcp-agent-tools/index.mdx: Updated is in the future: 2026-10-20.Browser check (final build,
dist/served byastro preview, Playwright Chromium at/opt/pw-browsers/chromium)scratchpad/issue-230/shots.mjs: 413 of 413 assertions pass (shots/results.json). The article in en, zh-Hans, ja and ko at 1366×625, 1440×750, 1512×830, 1920×945, 390×844 and 360×800, light and dark (prefers-color-scheme, which the site honours), lazy images scrolled into view: HTTP 200,scrollWidthequal to the viewport, no element past the viewport outside a scroll container, cover renders, every body image loads, no repeated image. The updated post in en at 1440 and 390 (it has no zh-Hans). The en blog list at 1440 and 390 links the new post. Element crops of the table, both diagrams and the first code block at 360 and 1366 in en and zh-Hans. The six served SVGs opened at native size: lowest text contrast 5.22:1 (en and zh table diagrams, "ExecutionContext → RBAC · RLS · FLS"), 5.42:1 (covers), 0 text nodes on a dark fill.The check found one defect, fixed in
b567417: the "not attempted" / "未尝试" cells of the two table diagrams read 3.74:1; they now use the diagram's small-text grey, 6.2:1 on white. Looked at: the folds at every width in en, zh-Hans at 1440 and 360 dark, ja at 390, ko at 1920 dark and 390 dark, the phone table (horizontal scroll container, as the site's phone rule gives every post), the diagrams at 328 px (the known site-wide phone size), the covers and diagrams at native size, and the updated post at 1440 and 390 with its "Updated Oct 20, 2026" line.Deviations and notes
updatedon the sibling is2026-10-27T10:00:00+08:00, the publish day, as ruled.os devon port 3230 (the README's step says 3000; the port is a container choice and the post prints what the banner printed).四个承诺中的第三个) because the zh-Hant generator's whitelist did not claim it and the whitelist is site code, out of scope.Acceptance notes (observations, not filed)
list_actionsrefuses anobjectNameargument as unrecognized (strict by design; the docs do not promise one).os devwithout--compileserves the previous artifact and says so loudly, naming the fix; by design.Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr