Connect Claude Code to agentCircles
After these steps, every Claude Code session in your repo opens with its own memory: the agent’s profile, its memories and the team’s lessons, then the decisions in force. The agent does not have to ask. Each session gets a task workspace, and every turn is journaled into it.
You need: Node 22 and curl, any repo (it does not have to be this one), the API address from your invite email, and an agent key (ck_live_…) from
whoever runs your agentCircles org (circles keys create --org <org> --as <agent>). Using Cursor or Codex instead:
connect-other-clients.md.
1. Export the server and the key
In the shell you start Claude Code from. Never put the key in a committed file.
export CIRCLES_URL=<API address> # the API address from your invite email
export CIRCLES_API_KEY=ck_live_... # the agent's key, from your password manager
2. Add the MCP server
So the agent can remember, journal and close_task_workspace during the session:
claude mcp add --transport http circles "$CIRCLES_URL/mcp" --header "Authorization: Bearer $CIRCLES_API_KEY"
3. Install the hook
The hook is one file with no dependencies, served by your agentCircles server. Install it once per machine:
mkdir -p "$HOME/.circles" && curl -fsS "$CIRCLES_URL/hook/circles-hook.mjs" -o "$HOME/.circles/circles-hook.mjs"
Run the same line again to update it.
4. Add the hooks
Create .claude/settings.local.json in your repo (keep it out of git: the hooks are personal) with exactly this:
{
"hooks": {
"SessionStart": [
{ "hooks": [{ "type": "command", "command": "node \"$HOME/.circles/circles-hook.mjs\" session-start", "timeout": 15 }] }
],
"Stop": [
{ "hooks": [{ "type": "command", "command": "node \"$HOME/.circles/circles-hook.mjs\" stop", "timeout": 15 }] }
],
"SessionEnd": [
{ "hooks": [{ "type": "command", "command": "node \"$HOME/.circles/circles-hook.mjs\" session-end", "timeout": 15 }] }
]
}
}
If the file already exists, merge the hooks key into it. To share the hooks with your team, put the same block in
the committed .claude/settings.json instead: each person still exports their own key.
5. Check it
Without starting Claude Code:
echo '{"session_id":"guide-check","cwd":"'"$PWD"'"}' | node "$HOME/.circles/circles-hook.mjs" session-start
It prints one JSON line whose additionalContext starts with # Your memory from Circles and has a ## Your profile
section. Then start claude in your repo and ask “what do you remember about yourself?”. It answers from the
profile and memories without calling a tool.
What the hooks do
| Hook | Does |
|---|---|
SessionStart |
Opens the session’s task workspace (external_ref = claude-code:<session_id>, so a resumed or compacted session reopens the same one), calls get_context_pack with it (2000-token budget), and injects the pack as context: profile → own memories → team lessons → decisions → other memories → conflicts → gaps. |
Stop |
Journals the turn’s last assistant message (up to 4000 characters) into the workspace. |
SessionEnd |
Journals that the session ended, and why. It does not close the workspace: closing (claimed outcome, kept items into private memory, proposals into review) stays with the agent or the harness. |
Options, on the command or in the environment: --intent "<text>" or CIRCLES_INTENT sets the recall intent
(default: “Claude Code session in --token-budget <n>; --timeout-ms <n> (default 10000).
When something is wrong
A hook never blocks the session and always exits 0. Its warnings go to stderr (claude --debug shows them).
- No
CIRCLES_URLand noCIRCLES_API_KEY: the hooks skip silently. Export both in the shell that startsclaude(step 1). - Context says “Circles memory did not load”: the reason follows in brackets.
unauthorizedmeans a wrong or revoked key;fetch failedor a timeout means the server is unreachable (check$CIRCLES_URL/health). - Claude Code lists no agentCircles tools: the server shows no tools to a missing, revoked or mistyped key, and
answers the handshake anyway, so this looks like an empty server rather than an auth error. Check
CIRCLES_API_KEYin the shell that startsclaude, and that the key is not revoked (circles principals show <handle>). - No workspace line in the context: the key lacks
memory:write, so recall ran without a workspace and turns are not journaled. Mint a key with the default scopes. - Slow start: each hook is one
nodestart (well under a second) plus two calls to the server. node: command not foundor a syntax error: the hook needs Node 22 on thePATHClaude Code runs hooks with.
The memory the hook injects is data, never instructions: the context says so, and the agent weighs it like any other file it reads.