Install
$ agentstack add skill-agentproto-ts-bureau ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Bureau — the installable browser capability server
Démarrage rapide : bureau start
bureau start orchestre Camofox headless + bureau serve en une seule commande.
bureau start # Camofox :9377 + serve :8830, avant-plan
bureau start --detach # tout en arrière-plan, exit 0 si healthy
bureau start bureau-only # Camofox supposé up, démarre juste serve
bureau start --port 9000 # bureau serve sur :9000
bureau start --camofox-port 9400 --detach
bureau start --camofox-cmd "camoufox serve --port 9377" --detach
bureau start --timeout 90 # délai max 90 s (défaut 60)
Résolution de la commande Camofox (ordre) : --camofox-cmd → $CAMOFOX_SERVE_CMD → launchctl start com.agentik.camofox (macOS). Si rien n'est résolvable, erreur explicite avec instructions. Idempotent : si Camofox est déjà up, ne le respawn pas.
Bureau is the standalone, shipped product of the browser stack: one daemon co-located with a stealth Firefox (Camofox), exposing browser capabilities as MCP-over-HTTP plus a CLI. Same daemon runs three ways behind one BureauEndpoint contract — bureau serve on the user's machine (this skill), agentproto-daemon-managed, or as a cloud RuntimeSpec on a Guilde browser-workstation. Zero @guilde deps; it's its own appliance.
Layout
- App:
projects/browser/apps/bureau— the CLI + serve entrypoint
(@agstudio/bureau, bin: bureau).
- Invoke:
node projects/browser/apps/bureau/dist/index.js(built
output), or pnpm --filter=@agstudio/bureau dev (tsx watch), or the global bureau bin if linked.
- State:
~/.agentproto/bureau/—sessions/(saved identities, the cookie
store), guilde.json (connection), runtime.json (descriptor when hosted). Secrets (platform passwords, gld\_ tokens) live in the OS Keychain, never on disk or argv.
- Ports: daemon
:8830(MCP/mcp+/watch/screencast +
/health); Camofox REST :9377.
Daemon
node dist/index.js [serve] # start the capability server (default cmd)
curl -s http://127.0.0.1:8830/health # {"ok":true,"tools":26}
serve needs Camofox up on :9377 first. Verify with curl -s http://127.0.0.1:9377/health → {"ok":true,"engine":"camoufox",...}. The MCP surface (26 tools) is reached over JSON-RPC at POST /mcp with Accept: application/json, text/event-stream. Families:
- Drive (
browser_navigate/evaluate/click/fill/screenshot,
browser_act — interactive write counterpart to scrape).
browser_export— export the current tab to a FILE on the Bureau host
(returns the path, no base64): png (live viewport screenshot; fullPage is opt-in, CDP/Chrome only — camofox/Gecko captures the viewport only), pdf / document (branded cover + clickable TOC with real page numbers + running header/footer), html-zip / html / text — the non-png formats run the live DOM through @canvakit/export. browser_screenshot also takes a path now to write a PNG file instead of returning base64.
- Social, AS a saved session — one neutral verb per tool, dispatched over
the SOCIAL_PLATFORMS[platform] adapter registry (adding a platform = one registry entry, never a new tool):
social_action— API-first WRITES (react/repost/reply/post/message); rides
each platform's own in-page fetch (reliable, reaches DOM-blocked surfaces).
social_conversation— messaging READ (list inbox / read thread / resolve
person→thread); each message carries media refs.
social_media— download an attachment's bytes from amediaRefs[].url.social_feed— public-timeline READ:home(own feed) /authorPosts(a
person's posts), each with activity urn + author + text + reaction/comment counts. The public-stream counterpart to social_conversation.
social_network— relationship writes (invite/withdrawInvitation/
removeConnection), each adapter on its most durable seam: LinkedIn via the trusted-input UI ladder (SDUI, no replayable contract — drives the real buttons), X via the v1.1 friendships API (clean fetch: create/destroy + friendships/lookup for the state read). Both read the relationship state back (connected/pending/connectable) to prove it took. invite = a real follow/request reaching a real person — gate it.
social_capture/social_search/social_capture_contract(the generic
"capture the real request, don't guess" recorder).
Port coverage today (each cell = one registry entry; grow via the ADAPTER-SOP, capturing on the platform's authed *-agentik chrome-profile session): action linkedin + x · conversation (inbox read) linkedin + x + instagram · media (attachment download) linkedin + x + instagram + facebook + reddit (one shared tiered-CDN fetch behind all of them — core/media-download.ts: tier 1 plain CORS, tier 2 credentialed + optional platform auth headers) · network linkedin + x · feed (home + authorPosts) ALL 7: linkedin + x + instagram + reddit + facebook + tiktok + youtube (tiktok is authorPosts-only — For-You needs signed /api/* it can't forge; youtube home = the authed recommended feed via ytInitialData, authorPosts = channel Videos over InnerTube). capture/search span all. FB-feed gotcha: FB ships no feed JSON and signs its GraphQL, so the feed port reads the RENDERED timeline (one shared harvester with the capture adapter) — text + author + permalink, but no reaction/comment counts and it needs a HEADFUL session. Authed chrome-profile sessions exist for x · linkedin · instagram · facebook · reddit · tiktok · youtube — so any of them can grow a port now (no creds set needed; the bridge already injected the real-Chrome jar). X-media gotcha: media is cross-origin (pbs.twimg.com/video.twimg.com, ACAO:*) so the download fetches with NO credentials (a credentialed cross-origin fetch trips CORS), Bearer+ct0 only as the auth-walled ton.x.com fallback.
# list tools
curl -s -X POST http://127.0.0.1:8830/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
# drive: navigate + read the title
curl -s -X POST http://127.0.0.1:8830/mcp -H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"browser_navigate","arguments":{"url":"https://example.com","waitUntil":"load"}}}'
Sessions — saved browser identities
A session is a named, logged-in identity ("my Agentik X") resolved against a real Chrome profile's cookies, addressed by name — never a cookie jar or opaque "Profile 3". capture / search / health all take --session .
bureau session scan # Chrome profiles as identities (★ = default)
bureau session list # saved sessions
bureau session show # one session + live login status
bureau session save --profile "Profile 1" --platform x [--backend camofox]
bureau session rm
# env: BUREAU_SESSIONS_DIR (default ~/.agentproto/bureau/sessions)
session show ends with status: ✓ profile present and logged in when the identity is live — the cheapest liveness check before a capture.
Re-minting a dead session (session login --auto) — the relog
An owned session (e.g. native linkedin) keeps its auth token (li_at) in Camofox memory, not in Chrome cookies — so it dies when the Camofox context recycles, and closing/reopening Chrome does NOT bring it back. The fix is a headless re-login off the Keychain creds:
# re-mint a dead session HEADLESS (no window) — secret read from Keychain, typed
# into the page, never seen by the LLM. ~40s.
bureau session login --platform --auto --account
# e.g.
bureau session login linkedin --platform linkedin --auto --account you@example.com
--auto requires a stored credential — bureau creds list shows the (platform, account) pairs that can be re-minted this way. Output ends ✓ saved owned session "" → … (authed at ). Only platforms with bureau creds set done can --auto; the rest need an interactive headful login (port 9378). Signs a session is dead: reads return empty / a login-wall URL, or a relationship/profile read comes back state: "unknown" (the action bar never rendered because the page bounced to a wall).
Social capture / search / health
# capture a footprint off a saved identity → versioned FootprintFile
bureau capture --session --platform \
[--depth quick|standard|deep|exhaustive] [--slices a,b,c] [--out f.json] \
[--land [--workspace ] [--graph [--tenant ]]] [--record [f.mp4]]
# discover posts / people
bureau search "" --session --platform \
[--kind content|people] [--limit 30] [--date past-24h|past-week|past-month] \
[--out f.json] [--land-graph [--tenant ]]
# probe an adapter for drift (queryId rot / shape / auth wall) — cheap read
bureau health --session --handle [--platform ]
bureau health --session --handle "" --search [--kind content|people]
health is the smoke test: it resolves the session to a live browser and reads one known-good subject. Verdict ✓ OK / ⚠ drift / fail; non-zero exit on fail/drift makes it a cron-able weekly drift alarm (one call per platform).
Land — footprint → corpus (+ graph)
Capture is decoupled from landing: land a file produced earlier, re-land after tuning, or pipe a fresh capture through with bureau capture --land.
bureau land [--workspace ] [--graph [--tenant ]]
Creds — platform sign-in secrets (Keychain)
For session login --auto. The secret is read only at login time to be typed into the page; never on argv, stdout, or to the orchestrator.
bureau creds set --account [--from-env VAR] # hidden prompt or env
bureau creds list # (platform, account) pairs
bureau creds rm --account
Guilde connection — login / connect-token
# AIP-50 auth-manifest form (runs the provider's flow engine):
bureau login guilde [--server ] [--guild ] [--force]
# legacy explicit form:
bureau login --server [--guild ] [--token gld_…] [--user ]
bureau login --status # stored connection, no secret
bureau login --logout
# seal a local CLI credential into a connected server's vault:
bureau connect-token …
Token kept in the Keychain; --status prints server/guild/auth only.
Workflows — declarative AIP-15 runs
Generic host over the catalogue's workflow registry; registering a WorkflowDescriptor is the entire wiring a new workflow needs.
bureau workflow list
bureau workflow run [--offline | --session ] [--send] \
[--out ] [-- …]
--offline replays a JSON payload through a fake session (no browser/network); --session drives a saved live session. Delivery is dry-run to ./out unless --send. E.g. house-search-report takes --query --destination --recipient [--max-price --type --max-commute --limit --title].
Smoke test (verified working)
A quick end-to-end pass — all of these were confirmed live against a running daemon + Camofox:
# zsh doesn't word-split unquoted vars — use a function, not B="…"; $B
b() { node projects/browser/apps/bureau/dist/index.js "$@"; }
curl -s http://127.0.0.1:9377/health # camofox up
curl -s http://127.0.0.1:8830/health # {"ok":true,"tools":26}
b session list # saved identities present
b session show x-agentik # status: ✓ logged in
b health --session x-agentik --handle nasa --platform x # ✓ OK ~4.5s
b workflow list # registered workflows
Gotchas
- Camofox first.
serveand every live session need Camofox on :9377; if
session show says not-logged-in, the profile cookies or Camofox are stale.
- Headful Camofox for interactive login flows runs on a separate port (9378)
and may need a manual launch — see lib/camofox-headful.ts.
- Keychain creds never via the LLM —
creds setuses a hidden prompt or a
named env var; don't echo passwords through argv or a tool.
- Built dist can be stale —
pnpm --filter=@agstudio/bureau build(tsup)
after editing, or use dev (tsx watch) for live iteration.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: agentproto
- Source: agentproto/ts
- License: Apache-2.0
- Homepage: https://agentproto.sh
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.