Local-first session bridge that lets AI agents borrow your authenticated browser sessions per-site, per-action, fully audited.
Project description
Coral — sudo for browser agents
Alpha — pre-audit. Coral has not yet undergone an external security review. The design (THREAT_MODEL.md) is transparent about what's defended and what isn't, but until a v1.0 release ships with a third-party review, treat Coral as experimental. Don't use it to broker sessions for accounts you can't afford to have compromised.
Coral is a local-first session bridge that lets AI agents borrow your already-authenticated browser sessions on a per-site, per-action, fully audited basis. You log in once in your real Chrome — passing 2FA, captchas, whatever — and Coral persists the resulting authenticated state in a passphrase-encrypted vault. When an agent needs to act on that site, Coral spins up a fresh isolated Chromium with your session restored and hands the agent a CDP URL it can drive. The agent never sees your password.
How it fits together
- Python daemon + CLI (this repo) — vault, HTTP API, MCP server, Playwright session manager, policy engine.
- Chrome extension (
extension/) — captures sessions from your normal browsing. Submitted to the Chrome Web Store; while the listing is under review, load it unpacked as shown below. - MCP — any MCP-speaking agent (Claude Desktop, Cursor, Claude Code, browser-use, Stagehand, …) drives Coral over stdio or local HTTP.
What it looks like in your code
The dominant use case is embedding Coral as a session manager inside your own agent code. You log in to a site once in your real Chrome, Coral persists the session in an encrypted vault, and your application hands the agent of your choice an authenticated, isolated browser via CDP. The agent never sees a password.
Here's the whole pattern with browser-use:
from mcp import ClientSession
from mcp.client.stdio import StdioServerParameters, stdio_client
from browser_use import Agent, Browser
from langchain_openai import ChatOpenAI
async def run_against_my_session(task: str, origin: str) -> str:
"""Drive an authenticated browser via an LLM, without ever handling
the user's password. Coral owns the session; browser-use drives it."""
server = StdioServerParameters(command="coral", args=["mcp-stdio"])
async with stdio_client(server) as (r, w), ClientSession(r, w) as coral:
await coral.initialize()
listing = await coral.call_tool("coral_list_sessions", {})
sessions = listing.structuredContent["sessions"]
chosen = next(
s for s in sessions if s["origin"] == origin and s["state"] == "active"
)
opened = await coral.call_tool(
"coral_open_session",
{"session_id": chosen["session_id"], "purpose": task},
)
cdp_url = opened.structuredContent["cdp_url"]
handle = opened.structuredContent["session_handle"]
try:
agent = Agent(
task=task,
llm=ChatOpenAI(model="gpt-4o"),
browser=Browser(cdp_url=cdp_url), # Coral's isolated Chromium
)
return str(await agent.run())
finally:
await coral.call_tool("coral_close_session", {"session_handle": handle})
That snippet drops into any Python codebase — a CLI subcommand, a
FastAPI handler, a worker, a notebook cell. Coral provides the
authenticated, policy-checked browser; browser-use provides the
LLM-driven action loop. They meet at the CDP URL. Every navigation
the agent makes still flows through Coral's policy engine; denied
paths abort before the network call.
The same pattern works with Stagehand
in TypeScript, or with the raw mcp SDK + Playwright if you're
building your own action loop —
see examples/ for both.
Requirements
- Python 3.11+ (
piporuv). - macOS or Linux. Windows isn't supported yet.
- SQLCipher native library — install before
pip install coralbridge, becausesqlcipher3builds against it:- macOS —
brew install sqlcipher - Debian / Ubuntu —
sudo apt install libsqlcipher-dev - Fedora / RHEL —
sudo dnf install sqlcipher-devel - Arch —
sudo pacman -S sqlcipher
- macOS —
- Node 20+ — only required if you want to build the Chrome extension from source. Otherwise grab the pre-built zip from the latest GitHub release.
Install
pip install coralbridge
playwright install chromium
That's it. coral is now on your PATH ready to run.
Working from a checkout instead (recommended for contributors):
git clone https://github.com/noelschwarz/coral
cd coral
uv sync --all-extras
uv run playwright install chromium
After uv sync, use uv run coral … everywhere — or run uv tool install .
to get the coral script on your PATH without prepending uv run.
Quickstart
Three terminal commands and three Chrome clicks. End-to-end under a minute.
1. Start the daemon
coral up
coral up initializes the encrypted vault on first run (asks for a
passphrase), starts the daemon in the background, and copies a pairing
challenge to your clipboard.
2. Load the extension
Pre-built bundle (recommended) — no Node.js required. Grab
coral-extension.zip from the latest release,
unzip it into any directory, and load that directory in Chrome (step 3
below).
mkdir -p ~/coral-extension && cd ~/coral-extension
curl -L -o coral-extension.zip \
https://github.com/noelschwarz/coral/releases/latest/download/coral-extension.zip
unzip -o coral-extension.zip
Build from source — only if you want unreleased extension changes:
cd extension
npm ci
npm run build
# load extension/dist/ in Chrome
In Chrome:
- Open
chrome://extensions. - Toggle Developer mode (top-right).
- Click Load unpacked and select the directory from the step above
(
~/coral-extension/for the pre-built bundle, orextension/dist/when building from source). - Pin the Coral icon to your toolbar.
- Click the icon — the popup auto-detects the clipboard challenge — and press Pair.
3. Capture a session
- Navigate to any site you're already logged into.
- Click the Coral icon → Capture session.
Verify from the terminal:
coral status # daemon state, active sessions, connected agents
coral list # captured sessions
That's it — an MCP agent can now open this session via coral_open_session.
Make it permanent
So you don't have to keep a terminal open or re-run coral up after every
reboot:
coral install-service
That writes a launchd LaunchAgent (macOS) or systemd --user unit (Linux)
and stores the vault passphrase in your OS keychain
(ADR-017). The daemon now starts
automatically on login.
To undo:
coral uninstall-service
Wire Coral into your MCP client
If you'd rather have your IDE-resident agent (Claude Desktop, Cursor, Claude Code) call Coral on its own — instead of embedding the snippet above in your own code — one command writes the config:
coral mcp install --client claude-desktop # or: cursor, claude-code
That writes a coral MCP-server entry into the client's config file
(no JSON editing). Restart the client and it'll spawn coral mcp-stdio
on demand. The LLM in your IDE can then call coral_list_sessions /
coral_open_session / coral_close_session itself as part of any chat
task. coral mcp status --client <name> shows the current entry;
coral mcp uninstall --client <name> removes it.
For embedding Coral inside your own application code, see the
snippet above and the
examples/ directory:
examples/browser_use/— Python + browser-use LLM agent.examples/stagehand/— TypeScript + Stagehand.examples/python_mcp/— rawmcpSDK + Playwright for custom action loops.
Per-session Chromium isolation (ADR-010) keeps every session in its own sandboxed profile no matter which client drives it.
Copy, modify, and discard.
Daily commands
coral status # daemon state, sessions, agents
coral list # captured sessions
coral revoke https://example.com # revoke session(s) for an origin
coral audit --since 0 --limit 50 # tail the audit log
coral panic --yes # revoke everything + stop daemon
coral diagnose # install + security self-check
coral keychain status # is the vault passphrase stashed?
Policy & review
Each origin has a YAML policy declaring allowed_paths, denied_paths,
rate limits, and review thresholds. Six bundled behavior packs (GitHub,
Gmail, Linear, LinkedIn, Notion, Slack) seed at first run with
default_action: deny plus explicit allow-lists.
coral policy get https://github.com # print the active YAML
coral policy put https://github.com -f my.yaml # upload a new one
coral reviews list # pending operator reviews
coral approve <review_id>
coral deny <review_id>
Schema in docs/policy-language.md; rationale
in ADR-011.
Environment variables
CORAL_HOME— data directory (default~/.coral).CORAL_PASSPHRASE— non-interactive passphrase forinit/start(CI and scripts only — prefer the OS keychain for daily use).CORAL_HTTP_PORT,CORAL_MCP_HTTP_PORT— port overrides. The host is always127.0.0.1(ADR-008).CORAL_DIAG_LEVEL— structured stderr log filter (debug|info|warn|error, defaultinfo).
Docs
coral-engineering-spec.md— source of truth.docs/architecture.md— current module map.THREAT_MODEL.md— what Coral defends against (and what it doesn't).docs/policy-language.md— YAML policy schema.SECURITY.md— vulnerability reporting policy.CHANGELOG.md— release history.docs/release-process.md— tagging, building, attaching the extension zip, publishing to PyPI.docs/ADR-006…docs/ADR-018— individual architectural decisions.
Contributing
See CONTRIBUTING.md for the dev workflow, quality
gates, and DCO sign-off requirements. The project follows the
Contributor Covenant 2.1.
Community
- Questions, design discussions, show-and-tell: GitHub Discussions.
- Bugs and feature requests: GitHub Issues.
- Security reports: use private vulnerability reporting,
not a public issue. Details in
SECURITY.md.
License
Licensed under the Apache License, Version 2.0. Contributions are accepted under the same terms.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file coralbridge-0.6.0.tar.gz.
File metadata
- Download URL: coralbridge-0.6.0.tar.gz
- Upload date:
- Size: 111.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
09bb71547f1fd8025e4082b26d57accaf75c4bcaecaf9e42b12c4c3781307880
|
|
| MD5 |
1fa531e05ea5269a86f9e3f6f5cc05de
|
|
| BLAKE2b-256 |
938ca2127e8c17fc34d95f29bb17cf7dbfe2b40546e697a68325b5fceace8061
|
Provenance
The following attestation bundles were made for coralbridge-0.6.0.tar.gz:
Publisher:
release.yml on noelschwarz/coral
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
coralbridge-0.6.0.tar.gz -
Subject digest:
09bb71547f1fd8025e4082b26d57accaf75c4bcaecaf9e42b12c4c3781307880 - Sigstore transparency entry: 1630728623
- Sigstore integration time:
-
Permalink:
noelschwarz/coral@f037d9d1b1edfa25fdeef636a845e5b53d00c153 -
Branch / Tag:
refs/tags/v0.6.0 - Owner: https://github.com/noelschwarz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f037d9d1b1edfa25fdeef636a845e5b53d00c153 -
Trigger Event:
push
-
Statement type:
File details
Details for the file coralbridge-0.6.0-py3-none-any.whl.
File metadata
- Download URL: coralbridge-0.6.0-py3-none-any.whl
- Upload date:
- Size: 85.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cb6b5380bcd9e2e11e6bc0805d68f796c8a6eb0b8129463b26941e7e1dd60281
|
|
| MD5 |
cbb9ee85ccd026c280db846898369dd7
|
|
| BLAKE2b-256 |
86bdf47276d3d65b827b8aa062505cfdfe6a0299ba78b0d308676af64884eba2
|
Provenance
The following attestation bundles were made for coralbridge-0.6.0-py3-none-any.whl:
Publisher:
release.yml on noelschwarz/coral
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
coralbridge-0.6.0-py3-none-any.whl -
Subject digest:
cb6b5380bcd9e2e11e6bc0805d68f796c8a6eb0b8129463b26941e7e1dd60281 - Sigstore transparency entry: 1630728685
- Sigstore integration time:
-
Permalink:
noelschwarz/coral@f037d9d1b1edfa25fdeef636a845e5b53d00c153 -
Branch / Tag:
refs/tags/v0.6.0 - Owner: https://github.com/noelschwarz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f037d9d1b1edfa25fdeef636a845e5b53d00c153 -
Trigger Event:
push
-
Statement type: