Connect Google, a terminal, an iPhone and a browser
Everything below is one call with a scoped token. The token decides which tools run, how many times, until when, and whose keys they use. Every call and every answer is a row on the Ledger.
1. The one call
Every tool of this build runs through one address. Send its name and its arguments with a token:
{
"method": "POST",
"url": "https://miscsubjects.com/g/run",
"headers": {
"authorization": "Bearer $MISC_TOKEN",
"content-type": "application/json"
},
"body": {
"tool": "NOW",
"args": {}
}
}As a command line:
curl -sS -X POST https://miscsubjects.com/g/run \
-H "authorization: Bearer $MISC_TOKEN" \
-H 'content-type: application/json' \
--data '{"tool":"NOW","args":{}}'The answer is JSON: ok, result (the tool's answer), error when it failed, call_id and receipt (the Ledger record of the call). A refused call says which limit refused it.
| Way | The call |
|---|---|
| REST | POST https://miscsubjects.com/g/run, header Authorization: Bearer <token>, body {"tool","args"} |
| Link | GET https://miscsubjects.com/g/run/<TOOL>?args=<JSON>&t=<token>: a browser, a Shortcut, a bookmark |
| MCP | POST https://miscsubjects.com/g/mcp with the token as Bearer, or https://miscsubjects.com/g/mcp?t=<token> for clients that take only an address. It lists only the tools the token allows. |
| Every way for one tool | GET https://miscsubjects.com/g/contracts/<TOOL>?t=<token>: each way written out whole with that token in it |
| What a token allows | GET https://miscsubjects.com/g?t=<token>: its limits in plain words |
2. Get a token
The owner makes tokens in the Console (Scoped access): pick the tools, the ways, the uses, the expiry, a task, and whose keys it runs with. The same thing as a call, on the owner's Mac (the build key is read from its file, never written down):
curl -sS -X POST https://miscsubjects.com/api/grants \
-H "x-sheets-key: $(cat ~/.misc-sheets-key)" \
-H 'content-type: application/json' \
--data '{"label":"Alice","tools":["GOOGLE_AS","IMSG_SEND_AS","MAC_EXEC_AS","CHROME_OPEN_AS","SEARCH","QUERY"],"ways":["rest","link","mcp"],"keys":"p_alice","ttl_s":2592000}'The answer holds token (starts g1.). Give it to the person; they keep it as MISC_TOKEN. A holder can make a narrower copy without asking the build (POST https://miscsubjects.com/g/narrow), never a wider one.
3. Their own keys
Whose keys (keys = p_k2x9qa): Every tool runs with this person’s own keys (their Gmail key, their iMessage line), never the build’s: a key they have not stored is a refusal that names it. It can only be set when the token is made; a narrower copy cannot change it. The holder adds and removes that person’s keys at /g/keys.
The person stores a key with their token. Values are sealed in storage and no address ever answers one back; only names are listed.
curl -sS -X POST https://miscsubjects.com/g/keys \
-H "authorization: Bearer $MISC_TOKEN" \
-H 'content-type: application/json' \
--data '{"name":"GOOGLE_REFRESH_TOKEN","value":"1//0g…"}'curl -sS https://miscsubjects.com/g/keys -H "authorization: Bearer $MISC_TOKEN" # the names they hold curl -sS -X DELETE "https://miscsubjects.com/g/keys?name=GOOGLE_REFRESH_TOKEN" -H "authorization: Bearer $MISC_TOKEN"
The rules a run for one person follows:
- Every key a tool's contract names, like
[GMAIL_API_KEY], is that person's. A name they have not stored is a refusal that names it. The build's own key is never used for them. - A tool whose contract has a key written into it, instead of named, is refused for them: it would spend the build's own.
- Code of the build that runs a tool (GOOGLE_AS, SEARCH, QUERY) sees only that person's keys.
- Whose keys a token uses is set when the token is made. A narrower copy cannot change it.
The owner can read and set a person's key names too: GET|POST|DELETE https://miscsubjects.com/api/people/<person id>/keys with the build key.
4. Google services
GOOGLE_AS calls any Google API (Gmail, Calendar, Drive, Sheets, Docs, YouTube, Search Console…) as the person's own Google account. It needs three keys from their own Google Cloud project:
- At console.cloud.google.com, make a project and turn on the APIs they will use (APIs & Services, Library: Gmail API, Google Calendar API, Google Drive API, Google Sheets API).
- OAuth consent screen: External, add their own address as a test user.
- Credentials, Create credentials, OAuth client ID, type Web application, with the redirect address
https://developers.google.com/oauthplayground. Keep the client ID and the client secret. - At developers.google.com/oauthplayground: the gear, "Use your own OAuth credentials", paste the two. Pick the scopes (for example
https://mail.google.com/,https://www.googleapis.com/auth/calendar,https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/spreadsheets), Authorize, then "Exchange authorization code for tokens". Keep the refresh token. - Store the three with their token:
curl -sS -X POST https://miscsubjects.com/g/keys \
-H "authorization: Bearer $MISC_TOKEN" \
-H 'content-type: application/json' \
--data '{"name":"GOOGLE_CLIENT_ID","value":"123…apps.googleusercontent.com"}'
curl -sS -X POST https://miscsubjects.com/g/keys \
-H "authorization: Bearer $MISC_TOKEN" \
-H 'content-type: application/json' \
--data '{"name":"GOOGLE_CLIENT_SECRET","value":"GOCSPX-…"}'
curl -sS -X POST https://miscsubjects.com/g/keys \
-H "authorization: Bearer $MISC_TOKEN" \
-H 'content-type: application/json' \
--data '{"name":"GOOGLE_REFRESH_TOKEN","value":"1//0g…"}'Then:
Send a mail from their Gmail
curl -sS -X POST https://miscsubjects.com/g/run \
-H "authorization: Bearer $MISC_TOKEN" \
-H 'content-type: application/json' \
--data '{"tool":"GOOGLE_AS","args":{"gmail_send":{"to":"someone@example.com","subject":"Hello","text":"Sent from my own Gmail through the build."}}}'Search their mail
curl -sS -X POST https://miscsubjects.com/g/run \
-H "authorization: Bearer $MISC_TOKEN" \
-H 'content-type: application/json' \
--data '{"tool":"GOOGLE_AS","args":{"url":"https://gmail.googleapis.com/gmail/v1/users/me/messages","query":{"q":"from:stripe newer_than:7d","maxResults":10}}}'Their next ten calendar events
curl -sS -X POST https://miscsubjects.com/g/run \
-H "authorization: Bearer $MISC_TOKEN" \
-H 'content-type: application/json' \
--data '{"tool":"GOOGLE_AS","args":{"url":"https://www.googleapis.com/calendar/v3/calendars/primary/events","query":{"singleEvents":true,"orderBy":"startTime","timeMin":"2026-10-05T00:00:00Z","maxResults":10}}}'Read a sheet
curl -sS -X POST https://miscsubjects.com/g/run \
-H "authorization: Bearer $MISC_TOKEN" \
-H 'content-type: application/json' \
--data '{"tool":"GOOGLE_AS","args":{"url":"https://sheets.googleapis.com/v4/spreadsheets/SPREADSHEET_ID/values/Sheet1!A1:F50"}}'Their newest Drive files
curl -sS -X POST https://miscsubjects.com/g/run \
-H "authorization: Bearer $MISC_TOKEN" \
-H 'content-type: application/json' \
--data '{"tool":"GOOGLE_AS","args":{"url":"https://www.googleapis.com/drive/v3/files","query":{"orderBy":"modifiedTime desc","pageSize":10,"fields":"files(id,name,mimeType,modifiedTime)"}}}'Args: url (only addresses on googleapis.com), method (default GET), query, body, headers; or gmail_send: {to, subject, text, cc, bcc}. The access token is made from the refresh token for each call and never kept.
5. Terminal
curl
Every example on this page is a command line. Keep the token in the shell:
export MISC_TOKEN='g1.…'
curl -sS -X POST https://miscsubjects.com/g/run \
-H "authorization: Bearer $MISC_TOKEN" \
-H 'content-type: application/json' \
--data '{"tool":"SEARCH","args":{"q":"gmail"}}'Node, Bun, Deno, a script
starter/call.mjs in the build is the whole client:
import { call } from './call.mjs'; // MISC_TOKEN in the environment
const r = await call('GOOGLE_AS', { gmail_send: { to: 'a@b.com', subject: 'Hi', text: 'Hello' } });
console.log(r.result);Claude Code, Codex, Cursor (MCP)
claude mcp add --transport http scoped-now 'https://miscsubjects.com/g/mcp' --header 'Authorization: Bearer $MISC_TOKEN'
# ~/.codex/config.toml
[mcp_servers.misc]
url = "https://miscsubjects.com/g/mcp"
http_headers = { Authorization = "Bearer g1.…" }The model sees only the tools the token allows, and every call it makes is on the Ledger under that token.
Python
import os, requests
r = requests.post("https://miscsubjects.com/g/run", headers={"authorization": "Bearer " + os.environ["MISC_TOKEN"]}, json={"tool": "NOW", "args": {}})
print(r.json())6. Their own Mac: terminal, iMessage, Chrome, Shortcuts
A person's Mac becomes reachable with one file, starter/mac-bridge/bridge.mjs (Node 18 or later, no packages), and a Cloudflare tunnel:
export MAC_BRIDGE_KEY=$(openssl rand -hex 24) node bridge.mjs # listens on 127.0.0.1:3737 brew install cloudflared printf 'ingress:\n - service: http://127.0.0.1:3737\n' > bridge-tunnel.yml # its own file: a ~/.cloudflared/config.yml with other rules answers 404 cloudflared tunnel --config bridge-tunnel.yml --url http://127.0.0.1:3737 # prints https://<words>.trycloudflare.com
They store the address and the key with their token:
curl -sS -X POST https://miscsubjects.com/g/keys \
-H "authorization: Bearer $MISC_TOKEN" \
-H 'content-type: application/json' \
--data '{"name":"MAC_BRIDGE_URL","value":"https://<words>.trycloudflare.com"}'
curl -sS -X POST https://miscsubjects.com/g/keys \
-H "authorization: Bearer $MISC_TOKEN" \
-H 'content-type: application/json' \
--data '{"name":"MAC_BRIDGE_KEY","value":"<the same value as MAC_BRIDGE_KEY>"}'| Tool | Args | What it does on their Mac |
|---|---|---|
MAC_EXEC_AS | {"cmd","args":[],"cwd","timeout"} | Runs a program and answers code, stdout and stderr |
IMSG_SEND_AS | {"to","text"} | Sends an iMessage from the account signed in to Messages |
CHROME_OPEN_AS | {"url"} | Opens a page in their Chrome |
CHROME_TABS_AS | {} | Every open tab: window, index, title, address |
CHROME_JS_AS | {"js"} | Runs JavaScript in the front tab (Chrome: View, Developer, Allow JavaScript from Apple Events) |
SHORTCUT_RUN_AS | {"name","input"} | Runs one of their Shortcuts |
curl -sS -X POST https://miscsubjects.com/g/run \
-H "authorization: Bearer $MISC_TOKEN" \
-H 'content-type: application/json' \
--data '{"tool":"IMSG_SEND_AS","args":{"to":"+14155551212","text":"On my way"}}'The first iMessage, Chrome or Shortcuts call asks the Mac for permission (System Settings, Privacy & Security, Automation); they allow it once. A quick tunnel's address changes when it restarts; a named tunnel (cloudflared tunnel create) keeps one.
7. iPhone
A Shortcut that runs a tool
- New Shortcut, add Get Contents of URL. URL:
https://miscsubjects.com/g/run. - Method POST. Headers:
Authorization=Bearer g1.…,Content-Type=application/json. - Request Body: JSON, with
tool(Text) =GOOGLE_ASandargs(Dictionary) holding the tool's arguments. - Add Get Dictionary Value for
result, then Show Result or Speak Text.
Run it from the home screen, Siri, the Action button, or an automation (arriving somewhere, a time of day, a message from someone).
A link on the home screen
The link way needs no Shortcut: Safari, Share, Add to Home Screen.
https://miscsubjects.com/g/run/NOW?args=%7B%7D&t=%24MISC_TOKEN
Make that token narrow (one tool, a few uses): whoever has the link can run it.
Text from their own number
Their iPhone and Mac share one iMessage account, so IMSG_SEND_AS on their Mac (section 6) sends from their own number. SHORTCUT_RUN_AS runs a Shortcut synced from the iPhone.
8. Browser
From any page
fetch('https://miscsubjects.com/g/run', {
method: 'POST',
headers: { authorization: 'Bearer ' + token, 'content-type': 'application/json' },
body: JSON.stringify({ tool: 'SEARCH', args: { q: 'invoice' } }),
}).then((r) => r.json()).then(console.log);The doors answer any origin (CORS is open); the token is the only credential.
A model in the browser (claude.ai, ChatGPT connectors)
Add a custom connector with the address https://miscsubjects.com/g/mcp?t=g1.…. The model sees only the token's tools.
A model that can only open links
Give it the link way: https://miscsubjects.com/g/run/<TOOL>?args=<JSON>&t=<token>. It answers JSON.
Their own Chrome
CHROME_OPEN_AS, CHROME_TABS_AS and CHROME_JS_AS drive the Chrome on their Mac through the bridge (section 6), with their sign-ins.
9. Workers on any host
A worker needs only the address and a token: no database password, no other key. The build's starter/ folder has one file per host, each a few lines around call.mjs:
| Host | File | Run it |
|---|---|---|
| Cloudflare Workers | starter/cloudflare/worker.js | npx wrangler deploy -c starter/cloudflare/wrangler.jsonc, then npx wrangler secret put MISC_TOKEN -c starter/cloudflare/wrangler.jsonc |
| Google Cloud Run, Fly, Render, a VPS | starter/node-server/server.mjs + Dockerfile | gcloud run deploy misc-starter --source starter --set-env-vars MISC_TOKEN=g1.… |
| AWS Lambda | starter/lambda/index.mjs | Node 22, a function URL, MISC_TOKEN in its environment; zip it with call.mjs beside the folder |
| Deno Deploy | starter/deno/main.ts | deployctl deploy starter/deno/main.ts, MISC_TOKEN in its settings |
The Cloudflare file also binds one shared D1 database, misc-shared: every copy of it (change name in the wrangler file) reads and writes the same tables. A worker elsewhere reaches data through the build's tools (QUERY, D1_QUERY) with its token, never with a Cloudflare key. Each worker gets its own token, so turning one token off stops one worker and no other.
10. Search and query
SEARCH looks for every word across the Directory, the Ledger, articles, tasks, stored objects and this build's routes. Each hit carries the QUERY that opens it.
curl -sS -X POST https://miscsubjects.com/g/run \
-H "authorization: Bearer $MISC_TOKEN" \
-H 'content-type: application/json' \
--data '{"tool":"SEARCH","args":{"q":"gmail refresh","in":["directory","ledger","tasks"],"limit":10}}'QUERY answers rows of one source with only the fields named in select. Dot paths reach inside a field.
curl -sS -X POST https://miscsubjects.com/g/run \
-H "authorization: Bearer $MISC_TOKEN" \
-H 'content-type: application/json' \
--data '{"tool":"QUERY","args":{"from":"ledger","where":{"tool":"GOOGLE_AS","from":"2026-10-01T00:00:00Z"},"select":["seq","ts","status","agent"],"limit":20}}'curl -sS -X POST https://miscsubjects.com/g/run \
-H "authorization: Bearer $MISC_TOKEN" \
-H 'content-type: application/json' \
--data '{"tool":"QUERY","args":{"from":"directory","where":{"type":"tool","description":{"contains":"imessage"}},"select":["name","description"],"limit":50}}'| from | What it reads |
|---|---|
directory | Every row of the Directory. Asking for a field beyond name, type and description reads each tool whole (its contracts too). |
ledger | The Ledger in its own database: where takes its fields (tool, agent, session, task, status, kind…) and from/to times (30 days by default); q is its word search. |
articles, tasks, api | Every article (no bodies), every task, every route of this build |
objects, objects:<kind> | Stored objects, all kinds or one |
where is {field: value} for equal, or {field: {"contains"|"in"|"gte"|"lte"|"ne": …}}. With the build key the same two are GET https://miscsubjects.com/api/search?q=… and POST https://miscsubjects.com/api/query.
This page is written by the build from the code it describes, each time it is opened. The scoped tokens themselves: /a/scoped-access.