Run Codex, Claude Code and OpenCode on your own Notion AI subscription.
Cogway is a local bridge. Your coding client thinks it is talking to OpenAI or Anthropic; the bridge translates each request into a Notion AI conversation and translates the answer back into the tool calls your client expects. Nothing leaves your machine except the Notion request itself.
🚀 Quick start in 5 minutes · 🇷🇺 Русская версия · 💬 Telegram: @oxyarmor
Warning
This is an unofficial integration with Notion's private API. It
authenticates with the token_v2 browser cookie, which is as sensitive as
your password. Automated access is very likely against Notion's terms of
service, and your account is the thing at risk. Read
Limits, scaling and risk before relying on it.
- How it works
- Requirements
- Install
- Getting your Notion token
- Using it
- Configuration
- Command reference
- Running several Notion accounts
- FAQ
- Troubleshooting
- Development
- Security and licence
- Author and feedback
┌───────────────┐ ┌──────────────┐ ┌───────────────┐
│ Codex CLI / │ │ Claude Code │ │ OpenCode │
│ Codex VS Code│ │ │ │ │
└───────┬───────┘ └──────┬───────┘ └───────┬───────┘
│ Responses │ Messages │ Chat Completions
└──────────────────┼───────────────────┘
▼
┌────────────────────────┐
│ bridge 127.0.0.1:8765│
│ │
│ planner protocol │ one JSON action envelope,
│ turns executor │ shared by all three adapters
│ state sessions │ one Notion thread per session
│ account_pool │ up to 10 sessions, failover
└───────────┬────────────┘
│ notion-agent-cli + token_v2
▼
┌────────────────────────┐
│ Notion AI │
│ fable-5 / gpt-5.6-sol │
│ / opus-5 │
└────────────────────────┘
The one thing worth understanding. Notion AI has no native tool calling. So the bridge asks the model for a JSON action envelope:
{"actions": [{"tool": "Read", "arguments": {"file_path": "src/app.py"}}]}and converts it back into a real tool_use / function_call for your client.
Your client still owns the agent loop, the approvals, the sandbox and the file
edits — the bridge only supplies the thinking.
Everything else follows from that:
| Piece | Job |
|---|---|
bridge/planner.py |
Builds the prompt, renders the tool catalog, parses and validates the actions that come back |
bridge/turns.py |
Leases an account, continues or starts a Notion thread, fails over, maps errors |
bridge/state.py |
Keeps one client session inside one Notion thread so history is not resent every turn |
bridge/account_pool.py |
Round-robin over your Notion sessions, per-account cooldown, circuit breaker |
bridge/*_api.py |
One adapter per client protocol |
notion-private-api-mcp/ |
Optional MCP server for reading and writing Notion pages |
runtime/ |
Optional local file/shell tools, for clients that bring none |
Models available through the bridge:
| Shown in your client | Bridge id | Codex transport id |
|---|---|---|
| Fable 5 (Notion) — default | fable-5 |
gpt-5.5 |
| GPT-5.6 Sol (Notion) | gpt-5.6-sol |
gpt-5.6-sol |
| Opus 5 (Notion) | opus-5 |
opus-5 |
Which of these you can actually use depends on your Notion plan. Run
cogway doctor --live after installing: it sends one short request per model
and tells you exactly which ones answer on your account.
Codex only accepts a fixed set of transport ids, which is why Fable travels as
gpt-5.5; the bridge maps it back. Claude Code's own model ids
(claude-sonnet-4-5-*, claude-opus-4-*, claude-3-5-haiku-*) are mapped
automatically, so /model opus and /model sonnet both work.
- Node.js 18+ and Python 3.10+ on
PATH - Git
- A Notion account with Notion AI enabled
- One of: Codex CLI, Codex for VS Code (
openai.chatgpt), Claude Code, OpenCode
Works on Windows 10/11, Linux and macOS. No root, no systemd, no admin rights.
Tip
Would rather not do this by hand? Install OpenCode. It installs independently of Cogway and runs on free models. Open this folder in it, pick a free model — DeepSeek V4 Flash, for example — and say "install this project following the instructions in AGENTS.md". The agent does everything below.
This needs plain opencode, not cogway opencode: the latter already
goes through the bridge, which does not exist yet. Claude Code and Codex
cannot run the install for the same reason — they have no provider until it
is finished.
Three commands on every platform.
git clone https://github.com/coldvisixn/cogway.git
cd cogway
cogway setupOn Linux and macOS write ./cogway setup. If the wrapper does not run at
all, node cli/index.mjs setup does exactly the same thing.
setup creates a Python virtual environment, installs dependencies, writes a
.env, registers every client it can find, and starts the bridge. It never
overwrites your existing editor settings — it merges into them and takes a
backup first.
Then add your Notion session:
cogway loginand confirm everything is healthy:
cogway doctor --liveWindows PowerShell — same commands
git clone https://github.com/coldvisixn/cogway.git
Set-Location .\cogway
cogway setup
cogway login
cogway doctorIf node is not recognised, install Node.js from nodejs.org and reopen the
terminal. If python opens the Microsoft Store, install Python from
python.org with Add Python to PATH ticked.
Useful setup options
# Restrict file tools to one directory instead of your whole home folder
cogway setup --code-root ~/projects
# Only register some clients
cogway setup --clients claude,codex
# Install without starting anything
cogway setup --no-start
# Also run the optional local-tools server
cogway setup --local-toolsOptionally, start the bridge with your user session:
cogway autostart # systemd --user, launchd, or Startup
cogway autostart --off # undocogway login walks you through this, but here it is in full:
- Open https://www.notion.so in a browser and sign in.
- Open DevTools (F12).
- Go to Application (Chrome/Edge) or Storage (Firefox) →
Cookies →
https://www.notion.so. - Find the row named
token_v2and copy its Value. - Run
cogway login, paste the value, press Enter, then Ctrl+Z and Enter on Windows, or Ctrl+D on Linux/macOS.
The token is read from stdin, so it never appears in your shell history or in
the process list. It is stored in ~/.notionagents/notion_account.json with
0600 permissions.
Treat this value like a password. It grants full access to your Notion workspace, not just to Notion AI. Signing out of Notion in the browser invalidates it, which is also how you revoke it if it leaks.
If login reports several workspaces, name the one you want:
cogway login --space-name "My Workspace"setup writes the provider settings into ~/.claude/settings.json. Restart
Claude Code and check with /status that the API base URL points at
127.0.0.1. Then use it normally:
> refactor the retry logic in src/http.py and run the tests
/model opus selects Notion Opus 5, /model sonnet selects Fable 5.
codexCodex reads the managed block in ~/.codex/config.toml and uses the Notion
provider automatically.
Install the official openai.chatgpt extension, run Developer: Reload
Window, open a new Codex chat and pick a Notion model. setup also applies a
small idempotent compatibility patch to the extension's model picker so that
Opus 5 (Notion) is listed. Rerun setup after the extension updates.
cogway opencodeThis launches OpenCode against an isolated profile in .runtime/opencode/, so
your global OpenCode configuration is left alone.
Everything lives in one .env at the repository root. Real environment
variables always win, which is how a second checkout runs beside the first.
See .env.example for the annotated list.
| Variable | Default | What it does |
|---|---|---|
COGWAY_BRIDGE_HOST |
127.0.0.1 |
Interface for the bridge. Keep it loopback: there is no authentication |
COGWAY_BRIDGE_PORT |
8765 |
Bridge port |
NOTION_AGENT_HOME |
~/.notionagents |
Where Notion sessions are stored |
CODE_ROOT |
your home | The furthest a file tool may reach |
COGWAY_INFERENCE_TIMEOUT_SECONDS |
180 |
When to give up on one Notion request and try another account |
COGWAY_REASONING_EFFORT |
high |
low, medium or high |
COGWAY_MAX_ACCOUNTS |
10 |
Upper bound on loaded Notion sessions |
COGWAY_LOCAL_TOOLS |
off |
Run the optional local-tools server |
COGWAY_RUNTIME_PORT |
8787 |
Port for that server |
MCP_PATH_SECRET |
generated | Required when local tools are on |
COGWAY_WORKFLOW_ID |
empty | Route inference through a specific Notion custom agent |
These are local settings. Raising a number here does not enlarge the real Notion model window — it only changes when your client decides to compact.
| Limit | Default | Where |
|---|---|---|
| Context window reported to Codex | 210,000 | cli/clients.mjs, config/codex-models.json |
| Auto-compaction threshold | 200,000 total | same |
| Tool output budget | 12,000 | same |
| OpenCode context / output | 100,000 / 40,000 | cli/clients.mjs |
Keep the compaction threshold below the reported window. After changing
anything, rerun setup and start a fresh chat.
Images are limited to 10 per request, 20 MiB each and 50 MiB in total, and are uploaded as native Notion attachments.
cogway setup [--code-root DIR] [--clients a,b] [--local-tools] [--no-start]
cogway login [--account auto|NAME] [--space-name NAME]
cogway logout [--account NAME | --all]
cogway start [--foreground] | stop | restart
cogway autostart [--off]
cogway status [--json]
cogway doctor [--live]
cogway update
cogway install <client...> | uninstall <client...>
cogway opencode [args...]
--live spends one Notion request per model per account; everything else is
free. npm run setup, npm start, npm run status and npm run doctor are
shortcuts for the same commands.
Adding more accounts never needs a name:
cogway login --account auto
cogway restartThe bridge can hold up to ten Notion sessions and spread new conversations across them. Add extras with:
cogway login --account account-02
cogway login --account account-03
cogway restartFiles live in ~/.notionagents/accounts/. Duplicates — same token_v2 or the
same Notion user — are detected and ignored, so you cannot accidentally
multiply one account.
An account whose allowance is spent, whose token expired, or which was
suspended keeps occupying its slot. Point login at that same slot and the new
token replaces the old one:
cogway status # find the disabled or cooling-down one
cogway login # replaces the primary session
cogway login --account account-02 # replaces that named session
cogway restartlogin says which file it is about to replace before asking for the token, and
the new token is checked against Notion first — if you paste a bad value the
working session stays. Use --account auto only when you are adding an
account: it takes the next free slot and leaves the dead one behind, and there
are only ten slots.
Replacing in place is enough on its own. A new token is a different account as far as the pool is concerned, so the old cooldown and disabled flag do not follow it — the slot starts clean.
If all ten slots hold dead accounts, free them and register new ones:
cogway logout # list what is stored
cogway logout --account account-02 # drop one
cogway logout --all # drop all of them and the pool bookkeeping
cogway login # register the first new session
cogway login --account auto # ...and each further one
cogway restartlogout on its own only lists; it never deletes without --account or
--all. A name it does not recognise is an error rather than a silent no-op,
so a typo cannot leave you believing a dead account is gone.
A new session picks the least recently used account and stays on it for the whole conversation, so the Notion thread is reused instead of resending history. On failure the account is put in cooldown and the request retries on the next one.
Before you scale this up, read Limits, scaling and risk. It covers where the real bottlenecks are, how rate limiting actually behaves, and the account-suspension risk you take on.
Does this use my Notion AI subscription? Yes. Every request is a normal Notion AI conversation on your account, and counts against whatever limits your plan has.
Is it against Notion's terms of service? Very likely. You are using a private API with a session cookie, from something that is not the Notion client. Nobody has published a carve-out for this. The risk is yours and it lands on your Notion account. See docs/scaling.md.
Does my code get sent to Notion? Only what your client puts in the prompt — the same code, file contents and tool results it would send to any other provider. The bridge itself stores no conversation content: session state on disk is hashes, ids and counters only.
Which client works best? Codex has the most mature path here. Claude Code is fully supported: multiple tool calls per turn, real streaming, thread reuse. OpenCode works through the OpenAI-compatible endpoint.
Can I use it with Cline, Roo, Continue, Zed or Aider?
They speak OpenAI Chat Completions or Anthropic Messages, so pointing them at
http://127.0.0.1:8765/v1 will probably work. It is not tested and not
supported; cogway install does not configure them.
Why not Gemini CLI or Cursor?
Gemini CLI speaks Google's generateContent protocol with its own OAuth, which
would need a whole separate adapter. Cursor requires a publicly reachable
HTTPS endpoint and will not accept a loopback address. Neither can be supported
well, so neither is claimed.
Why is one action per turn the default for Codex? It is not — the planner may return several independent actions in one envelope, and they are emitted as several output items. It only returns one when the next step genuinely depends on the previous result.
Can I run two checkouts at once?
Yes. Give the second one its own .env with a different COGWAY_BRIDGE_PORT,
or export the variables directly. Real environment variables override the file.
Does it work offline? No. Notion AI is the model.
Start with cogway doctor. It checks the toolchain, the
configuration, your credentials and the running services, and prints the exact
command to fix whatever it finds.
Run cogway setup, or copy .env.example to .env.
The bridge found no usable account file. Run cogway login, then
cogway restart — the pool is read once at startup.
Same cause: no valid Notion session. This is deliberately not a 503, so your
client stops retrying instead of looping on an unfixable error.
Not an installation problem. Notion rejected a request, so the bridge stops
using that session for a while and moves to the next. retry_after shows the
remaining seconds. If one account is permanently failing, refresh its
token_v2 with cogway login --account <name>.
Its token is invalid or the account has no Notion AI access. Replace that
session in place — cogway login for the primary one, cogway login --account account-02 for a named one — then cogway restart. See
Replacing the token of a dead account.
The token can reach several workspaces. Retry with
--space-name "Exact Workspace Name".
Confirm doctor is clean, run Developer: Reload Window, then open a new
chat — an already-running Codex app-server keeps its old configuration. If only
Opus is missing after an extension update, rerun setup.
Check the model aliases:
cogway doctor # verifies them for you~/.notionagents/models.json must map fable-5 → acai-budino-high,
gpt-5.6-sol → orange-mousse, opus-5 → agave-flan. A wrong alias silently
routes you to a smaller model. Do not guess replacements — rerun setup.
cogway stop # stops by pid, or by port if the pid file is gone
cogway startIf something else owns the port, change COGWAY_BRIDGE_PORT in .env and
rerun setup so the client configs follow.
Check /status inside Claude Code. If the base URL is not 127.0.0.1, an
ANTHROPIC_BASE_URL exported in your shell is overriding the settings file;
environment variables win over settings.json.
The Notion AI allowance on that account is spent. Notion does not report this through the API — it closes the stream with no content and no error, and shows the human-readable notice ("you have used up your Notion credit") only on notion.so. Open the site to confirm.
A paid plan's allowance resets on its own schedule. The free allowance is a one-time trial and does not return — Notion offers an upgrade instead. Cogway cannot change that; it takes the account out of rotation with an escalating pause so the exhausted session is not retried every 30 seconds.
The bridge is launched as a background process through PowerShell, which some antivirus products and SmartScreen treat as suspicious. Allow it, or add the project directory to the exclusions.
That model is not on your Notion plan. cogway doctor --live names the ones
that are; pick one of those.
It should not — the bridge is started outside the terminal's process group. If
it still happens, use cogway autostart to register it with your session
manager instead.
tail -f .runtime/logs/bridge.err.log # Linux / macOS
Get-Content .runtime\logs\bridge.err.log -Wait # WindowsLogs are structured JSON: request ids, account ids, segment numbers, selection
reason (balanced, affinity, failover), durations and error codes. Prompts,
tool results, cookies and images are never logged.
# Bridge tests
PYTHONPATH=bridge .runtime/notion-agent-cli-venv/bin/python -m unittest discover -s bridge/tests -v
# CLI and runtime tests
node --test cli/clients.test.mjs scripts/patch-codex-webview.test.mjs
npm --prefix runtime test
# Syntax checks and release audit
npm run check
node scripts/check-public-release.mjsRepository conventions for AI agents working on this codebase are in
AGENTS.md.
- The bridge binds to loopback and has no authentication. Do not expose it.
token_v2is never read, printed, copied or committed by any tooling here.- Client configs are merged, never replaced, and backed up before writing.
- Session state on disk contains no conversation content.
Report vulnerabilities as described in SECURITY.md. Run
node scripts/check-public-release.mjs before publishing.
Source-available, not open source: read it, run the copy you were licensed,
modify it for yourself — but do not redistribute or resell it. Full terms in
LICENSE. The vendored notion-private-api-mcp/ is third-party
code and keeps its own MIT licence.
Cogway is written by @oxyarmor — the developer's Telegram channel.
That is the place for:
- Ideas and feature requests. Which client to support next, which limit to make configurable, what the CLI should do that it does not.
- Bug reports from real use. Especially the ones a test suite cannot find: a Notion API change, a client update that breaks the model picker, an error message that says nothing useful.
- Release news. New versions and Notion-side breakage are announced there first, usually before the repository catches up.
- A thank you, if it saved you an afternoon. It is read, and it is the only payment the open part of this project asks for.