diff --git a/AI_Instructions/CODEX_INSTRUCTIONS.md b/AI_Instructions/CODEX_INSTRUCTIONS.md new file mode 100644 index 0000000..c804963 --- /dev/null +++ b/AI_Instructions/CODEX_INSTRUCTIONS.md @@ -0,0 +1,51 @@ +You have access to a personal second brain via MCP tools: remember, recall, list_recent, append, update, forget. + +MANDATORY RULES — no exceptions: + +1. At the start of EVERY conversation, call recall with a natural language query that describes both the topic AND what the user is trying to do. Frame it as 'User wants to X about Y – what should I know?' rather than just the topic keyword. Do not skip this even if the topic seems simple. + +2. Store EVERYTHING important automatically — call remember whenever the user mentions: + - Anything personal (goals, preferences, habits, relationships, health) + - Work context (projects, decisions, strategies, problems, progress) + - Ideas or plans (even half-formed ones) + - Tasks or commitments ("I need to", "I'm going to", "we decided") + - Opinions or reactions ("I think", "I like", "I don't want") + +3. Store important content from YOUR OWN responses too — call remember after responding whenever your response contains: + - A recommendation or decision you made on the user's behalf + - A plan, strategy, or approach you proposed + - A summary or conclusion you reached + - A technical solution, architecture, or code pattern you designed + - An answer to a question the user is likely to ask again + Store these as a condensed summary, not the full response. Tag with "codex-response" plus any relevant project tags. + +4. Never ask permission to store — store silently and keep going. + +5. NEVER rely on your own built-in memory or conversation history for facts about the user. If you would normally save a memory, call remember instead. Always. + +6. Auto-detect the current topic or project and include it as a tag (e.g. if discussing a website, tag it "website"; if discussing a specific company or product, use that name as a tag). Always combine specific tags with generic ones. + +7. Before making ANY recommendation, suggestion, or action item, first recall from memory to check if you have already made that recommendation or if the user has already completed it. Frame the query with intent: 'User is about to X — have I recommended this before or has it been done?' If it has already been recommended, acknowledge that and either confirm it's still the right move or suggest an alternative. Never repeat a recommendation without first checking. This applies to: promotion tasks, outreach targets, content to create, platforms to post on, people to contact, and any other repeatable action. + +8. ALWAYS pass context when calling recall — never use bare keywords. Every recall call must describe both the topic and the intent behind the query. Good: 'User wants to fix a bug in the capture flow — what have we tried before?' Bad: 'capture bug'. This applies to every recall call, not just the opening one. + +Tool guidance: +- **remember** — store a new piece of information (idea, fact, decision, preference). +- **append** — add new information to an existing entry without replacing the original. Use when something has changed or new details have emerged. Gets the entry ID from recall or list_recent first. +- **update** — fully replace the content of an existing entry. Use when information is outdated and should be overwritten entirely (e.g. a preference reversed, a plan scrapped, a location changed). Gets the entry ID from recall or list_recent first. Old vectors are cleaned up automatically. +- **recall** — semantically search stored memories. Always use an intent-framed natural language query (see rules 1 and 8). Call at the start of every conversation and whenever context is needed mid-conversation. +- **list_recent** — browse recent entries by date; useful when you need an entry ID. +- **forget** — permanently delete an entry by ID. Requires explicit user instruction. + +Tags to use: +- personal — life, preferences, habits, health, relationships +- work — projects, decisions, strategy, progress +- task — action items, to-dos, commitments, follow-ups ("I need to", "I'm going to", "we decided to"). ALWAYS tag these as task so they can be found with recall tag:task. +- idea — concepts, plans, brainstorms, half-formed thoughts +- context — background info about ongoing situations, constraints, environment +- codex-response — summaries of important responses or recommendations +- [auto-detected project/topic tag] — always combine with one of the above (e.g. ["task", "second-brain"]) + +Always set source to "codex" when storing. + +If the second brain MCP tools are unavailable, tell me immediately. Do not fall back to your own memory silently. diff --git a/README.md b/README.md index 8a6a44a..3121801 100644 --- a/README.md +++ b/README.md @@ -53,19 +53,24 @@ Memory is only useful if it actually gets filled. Second Brain connects to the t ----- -## Setup +## Quick Start -> **Before you deploy:** You’ll be asked to set an `AUTH_TOKEN`. This is the password your AI clients use to connect. -> -> **Quick option:** Use a memorable phrase like `coffee-lover-2026` -> -> **Secure option:** Run `openssl rand -base64 32` in your terminal and paste the result -> -> **Save it.** You’ll need it in the next step. +> **Before you deploy:** You’ll be asked to set an `AUTH_TOKEN` — the password your AI clients use to connect. Use a memorable phrase (`coffee-lover-2026`) or run `openssl rand -base64 32` for a stronger one. **Save it** — you'll need it in step 3. + +1. **[Deploy to Cloudflare](https://deploy.workers.cloudflare.com/?url=https://github.com/rahilp/second-brain-cloudflare)** — one click, everything provisions automatically. Set your `AUTH_TOKEN` when prompted. + +1. **Using Claude Code or Codex CLI?** Run one command and paste in your worker URL — it wires up global instructions *and* the MCP connection via OAuth, so your token never touches the script: -1. **Click Deploy** — everything provisions automatically -1. **Set your token** — you’ll be prompted during deploy -1. **Connect your AI tools** — [instructions here](../../wiki/Connect-to-AI-Clients) + ```bash + # macOS / Linux / WSL / Git Bash + curl -fsSL https://raw.githubusercontent.com/rahilp/second-brain-cloudflare/main/scripts/connect-ai-clients.sh | bash -s -- https://YOUR-WORKER-URL + ``` + ```powershell + # Windows (PowerShell) + iex "& { $(irm https://raw.githubusercontent.com/rahilp/second-brain-cloudflare/main/scripts/connect-ai-clients.ps1) } -WorkerUrl https://YOUR-WORKER-URL" + ``` + +1. **Using ChatGPT or Claude (desktop app or web)?** These need two quick manual steps in their UI — paste your custom instructions into their personalization settings, and add `https://YOUR-WORKER-URL/mcp` as a custom MCP connector. Each app's exact menus differ, so follow the **[per-app steps in the wiki](../../wiki/Connect-to-AI-Clients)**. That’s it. Your memory is live and ready across every tool you connect. @@ -78,14 +83,20 @@ curl -X POST https://YOUR-WORKER-URL/capture \ # → {"ok":true,"id":"..."} ``` -### OAuth for browser-based clients (claude.ai, ChatGPT) +### OAuth for browser-based clients + +The `/mcp` endpoint supports **OAuth 2.0** (discovery + dynamic client registration), +so any MCP client that can open a browser to authenticate connects without ever +putting a token in a config file or URL. When you add `https:///mcp` +as a connector, the client detects the `WWW-Authenticate` challenge, registers itself, +and opens the worker's hosted login +page; **enter your `AUTH_TOKEN`** there to authorize. claude.ai, ChatGPT, Claude Code +(`claude mcp add --transport http second-brain /mcp`, no `--header` needed), and +Codex CLI (`codex mcp add second-brain --url /mcp`, which detects OAuth support +and starts the login flow itself) all use this flow. -The `/mcp` endpoint also supports **OAuth 2.0**, so MCP clients that open a browser -to authenticate, like claude.ai and ChatGPT, can connect without putting a token in -the URL. When you add `https:///mcp` as a connector, you’ll see a -hosted login page; **enter your `AUTH_TOKEN`** to authorize. Claude Desktop, Claude -Code, and `mcp-remote` keep using the `Authorization: Bearer ` header as -before — no change needed. +Clients that can't open a browser — e.g. `mcp-remote` in headless contexts — can still +fall back to the static token via `Authorization: Bearer `. OAuth needs a KV namespace (`OAUTH_KV`) to store tokens and client registrations. diff --git a/scripts/connect-ai-clients.ps1 b/scripts/connect-ai-clients.ps1 new file mode 100644 index 0000000..d9dd714 --- /dev/null +++ b/scripts/connect-ai-clients.ps1 @@ -0,0 +1,128 @@ +<# +.SYNOPSIS + Wires up Second Brain for Claude Code and Codex CLI in one shot: + - appends global system instructions to ~/.claude/CLAUDE.md and ~/.codex/AGENTS.md + - registers the /mcp endpoint as an MCP server via OAuth (no token ever stored here) + +.USAGE + iex "& { $(irm /scripts/connect-ai-clients.ps1) } -WorkerUrl https://YOUR-WORKER-URL" +#> + +param( + [string]$WorkerUrl +) + +$ErrorActionPreference = "Stop" + +$RawBase = "https://raw.githubusercontent.com/rahilp/second-brain-cloudflare/main" +$StartMarker = "" +$EndMarker = "" +$SentinelPhrase = "At the start of EVERY conversation, call recall" + +if ([string]::IsNullOrWhiteSpace($WorkerUrl)) { + $WorkerUrl = Read-Host "Enter your Second Brain worker URL (e.g. https://your-worker.workers.dev)" +} + +$WorkerUrl = $WorkerUrl.TrimEnd("/") + +if ($WorkerUrl -notmatch "^https?://") { + Write-Error "Worker URL must start with http:// or https:// (got: $WorkerUrl)" + exit 1 +} + +$McpUrl = "$WorkerUrl/mcp" + +Write-Host "Worker URL: $WorkerUrl" +Write-Host "MCP endpoint: $McpUrl" +Write-Host "" + +function Append-Instructions { + param( + [string]$TargetFile, + [string]$SourcePath, + [string]$Label + ) + + $dir = Split-Path -Parent $TargetFile + if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } + if (-not (Test-Path $TargetFile)) { New-Item -ItemType File -Path $TargetFile -Force | Out-Null } + + $existing = Get-Content -Raw -ErrorAction SilentlyContinue $TargetFile + if ($null -eq $existing) { $existing = "" } + + if ($existing.Contains($StartMarker)) { + Write-Host "[$Label] Already configured (marker found in $TargetFile) - skipping." + return + } + + if ($existing.Contains($SentinelPhrase)) { + Write-Host "[$Label] Looks like you already pasted these instructions manually into $TargetFile - skipping to avoid duplicating." + return + } + + try { + $body = Invoke-RestMethod -Uri "$RawBase/$SourcePath" -ErrorAction Stop + } catch { + Write-Warning "[$Label] Could not fetch instruction body from $RawBase/$SourcePath - skipping." + return + } + + $block = "`n$StartMarker`n$body`n$EndMarker`n" + Add-Content -Path $TargetFile -Value $block + Write-Host "[$Label] Appended instructions to $TargetFile" +} + +Write-Host "-- Global instructions --" +Append-Instructions -TargetFile (Join-Path $env:USERPROFILE ".claude\CLAUDE.md") -SourcePath "AI_Instructions/CLAUDE_INSTRUCTIONS.md" -Label "Claude Code" +Append-Instructions -TargetFile (Join-Path $env:USERPROFILE ".codex\AGENTS.md") -SourcePath "AI_Instructions/CODEX_INSTRUCTIONS.md" -Label "Codex CLI" +Write-Host "" + +Write-Host "-- MCP server registration (OAuth - no token needed here) --" + +if (Get-Command claude -ErrorAction SilentlyContinue) { + $alreadyRegistered = $false + try { claude mcp get second-brain *> $null; $alreadyRegistered = $true } catch { $alreadyRegistered = $false } + + if ($alreadyRegistered) { + Write-Host "[Claude Code] 'second-brain' MCP server is already registered - skipping." + } else { + try { + claude mcp add --transport http second-brain $McpUrl + Write-Host "[Claude Code] Registered 'second-brain'. You'll be prompted to authorize in your browser on first use." + } catch { + Write-Warning "[Claude Code] Failed to register 'second-brain' - you can add it manually with:`n claude mcp add --transport http second-brain `"$McpUrl`"" + } + } +} else { + Write-Host "[Claude Code] 'claude' CLI not found on PATH - skipping." +} + +if (Get-Command codex -ErrorAction SilentlyContinue) { + $alreadyRegistered = $false + try { codex mcp get second-brain *> $null; $alreadyRegistered = $true } catch { $alreadyRegistered = $false } + + if ($alreadyRegistered) { + Write-Host "[Codex CLI] 'second-brain' MCP server is already registered - skipping." + } else { + try { + codex mcp add second-brain --url $McpUrl + Write-Host "[Codex CLI] Registered 'second-brain' and started the OAuth login flow." + } catch { + Write-Warning "[Codex CLI] Failed to register 'second-brain' - you can add it manually with:`n codex mcp add second-brain --url `"$McpUrl`"" + } + } +} else { + Write-Host "[Codex CLI] 'codex' CLI not found on PATH - skipping." +} + +Write-Host "" +Write-Host "-- Done --" +Write-Host "Reminders:" +Write-Host " - On first use you'll be prompted in your browser to enter your AUTH_TOKEN -" +Write-Host " that's the one-time OAuth handshake. (If you connect both Claude Code and" +Write-Host " Codex in the same browser session, you may only be asked once.)" +Write-Host " - Also using the ChatGPT or Claude apps (not Codex CLI / Claude Code)? Their" +Write-Host " personalization / custom-instruction settings are account-level and have no" +Write-Host " public write API - paste AI_Instructions/CHATGPT_INSTRUCTIONS.md into ChatGPT's" +Write-Host " Settings -> Personalization -> Custom Instructions, and a similar block into" +Write-Host " claude.ai's profile preferences, by hand." diff --git a/scripts/connect-ai-clients.sh b/scripts/connect-ai-clients.sh new file mode 100755 index 0000000..2a2fc23 --- /dev/null +++ b/scripts/connect-ai-clients.sh @@ -0,0 +1,123 @@ +#!/usr/bin/env bash +# Wires up Second Brain for Claude Code and Codex CLI in one shot: +# - appends global system instructions to ~/.claude/CLAUDE.md and ~/.codex/AGENTS.md +# - registers the /mcp endpoint as an MCP server via OAuth (no token ever stored here) +# +# Usage: +# curl -fsSL /scripts/connect-ai-clients.sh | bash -s -- https://YOUR-WORKER-URL + +set -euo pipefail + +RAW_BASE="https://raw.githubusercontent.com/rahilp/second-brain-cloudflare/main" +START_MARKER="" +END_MARKER="" +SENTINEL_PHRASE="At the start of EVERY conversation, call recall" + +WORKER_URL="${1:-}" + +if [[ -z "$WORKER_URL" ]]; then + read -rp "Enter your Second Brain worker URL (e.g. https://your-worker.workers.dev): " WORKER_URL +fi + +# Trim trailing slash(es) +while [[ "$WORKER_URL" == */ ]]; do WORKER_URL="${WORKER_URL%/}"; done + +if [[ ! "$WORKER_URL" =~ ^https?:// ]]; then + echo "Error: worker URL must start with http:// or https:// (got: $WORKER_URL)" >&2 + exit 1 +fi + +MCP_URL="${WORKER_URL}/mcp" + +echo "Worker URL: $WORKER_URL" +echo "MCP endpoint: $MCP_URL" +echo + +fetch() { + curl -fsSL "$1" +} + +# ─── Append instructions idempotently ──────────────────────────────────────── +append_instructions() { + local target_file="$1" + local source_path="$2" + local label="$3" + + mkdir -p "$(dirname "$target_file")" + touch "$target_file" + + if grep -qF "$START_MARKER" "$target_file" 2>/dev/null; then + echo "[$label] Already configured (marker found in $target_file) — skipping." + return + fi + + if grep -qF "$SENTINEL_PHRASE" "$target_file" 2>/dev/null; then + echo "[$label] Looks like you already pasted these instructions manually into $target_file — skipping to avoid duplicating." + return + fi + + local body + if ! body="$(fetch "${RAW_BASE}/${source_path}")"; then + echo "[$label] Could not fetch instruction body from ${RAW_BASE}/${source_path} — skipping." >&2 + return + fi + + { + echo + echo "$START_MARKER" + echo "$body" + echo "$END_MARKER" + } >> "$target_file" + + echo "[$label] Appended instructions to $target_file" +} + +echo "── Global instructions ──" +append_instructions "$HOME/.claude/CLAUDE.md" "AI_Instructions/CLAUDE_INSTRUCTIONS.md" "Claude Code" +append_instructions "$HOME/.codex/AGENTS.md" "AI_Instructions/CODEX_INSTRUCTIONS.md" "Codex CLI" +echo + +# ─── Register MCP server via OAuth ──────────────────────────────────────────── +echo "── MCP server registration (OAuth — no token needed here) ──" + +if command -v claude >/dev/null 2>&1; then + if claude mcp get second-brain >/dev/null 2>&1; then + echo "[Claude Code] 'second-brain' MCP server is already registered — skipping." + else + if claude mcp add --transport http second-brain "$MCP_URL"; then + echo "[Claude Code] Registered 'second-brain'. You'll be prompted to authorize in your browser on first use." + else + echo "[Claude Code] Failed to register 'second-brain' — you can add it manually with:" >&2 + echo " claude mcp add --transport http second-brain \"$MCP_URL\"" >&2 + fi + fi +else + echo "[Claude Code] 'claude' CLI not found on PATH — skipping." +fi + +if command -v codex >/dev/null 2>&1; then + if codex mcp get second-brain >/dev/null 2>&1; then + echo "[Codex CLI] 'second-brain' MCP server is already registered — skipping." + else + if codex mcp add second-brain --url "$MCP_URL"; then + echo "[Codex CLI] Registered 'second-brain' and started the OAuth login flow." + else + echo "[Codex CLI] Failed to register 'second-brain' — you can add it manually with:" >&2 + echo " codex mcp add second-brain --url \"$MCP_URL\"" >&2 + fi + fi +else + echo "[Codex CLI] 'codex' CLI not found on PATH — skipping." +fi + +echo +echo "── Done ──" +echo "Reminders:" +echo " • On first use you'll be prompted in your browser to enter your AUTH_TOKEN —" +echo " that's the one-time OAuth handshake. (If you connect both Claude Code and" +echo " Codex in the same browser session, you may only be asked once.)" +echo " • Also using the ChatGPT or Claude apps (not Codex CLI / Claude Code)? Their" +echo " personalization / custom-instruction settings are account-level and have no" +echo " public write API — paste AI_Instructions/CHATGPT_INSTRUCTIONS.md into ChatGPT's" +echo " Settings → Personalization → Custom Instructions, and a similar block into" +echo " claude.ai's profile preferences, by hand."