Skip to main content

🌳 CogSession

Session memory for AI coding agents. Your agent forgets everything when the context window fills. CogSession remembers the parts worth keeping, and tells you when they stop being true.

Python 3.11+ License: Apache 2.0 MCP Tests


The problem

Session 1 (context fills) → Session 2 starts fresh → Session 3 starts fresh
    Everything lost.          Repeats the mistakes.   Starts blind again.

You explain the codebase again. The agent tries the approach that already failed. The constraint you agreed on in session 1 is gone by session 3.

The usual answer is "write better notes", which fails for the same reason all documentation fails: it is true when written and nobody notices when it stops being true.

What CogSession does

Three things, and the third is the one that does not exist elsewhere.

1. It records without being asked. A session opens on its own. Decisions, dead ends, assumptions and errors are written as they happen, each stamped with the local time and the repo state it happened at (main@a1b2c3d+2, where +2 is dirty files).

2. It makes that searchable without loading it. Every session keeps a session.md: append-only, one block per event, every entry line self-describing. So one grep answers a question without pulling a file into context.

grep -A4 "dead_end"      .cogsessions/*/session.md   # what already failed
grep "2026-08-27 01:"    .cogsessions/*/session.md   # what happened that hour
grep "main@a1b2c3d"      .cogsessions/*/session.md   # what happened at that commit

3. It tells you when what you wrote stops being true. Record a claim with the command that proves it. When the files it watches change, the proof is re-run:

[CogSession] 1 claim(s) no longer hold:
  ✗ the composite key includes the tenant column
    expected '1', got '0'
    asserted in: PR description, line 26
    proof: grep -c 'UNIQUE (a, b, c)' migrations/007_schema.sql

No model judgement involved. It stores the command that proved something and re-runs it. Silence means everything still holds.

Why the third one matters

Every expensive failure in three weeks of daily use reduced to one sentence: something was true when it was written and stopped being true. A pull request description explaining a schema the code no longer had. A comment naming a constraint that moved. A test asserting a shape the implementation had dropped. A docstring contradicting its own function.

An agent cannot notice that from a transcript. A human notices it in review, which is the expensive place. A stored proof notices it for free.


What a session looks like on disk

.cogsessions/
├── sess_001_discover/
│   ├── session.md          ← greppable timeline, every entry timestamped + git-stamped
│   ├── handoff.md          ← the brief the next session reads first
│   ├── claims.json         ← assertions with the commands that prove them
│   ├── dead_ends.md        ← what failed and why, so it is not retried
│   ├── assumptions.md      ← what was assumed but never verified
│   ├── tasks.json          ← done / remaining / blocked
│   ├── decisions.json      ← flagged when made under high context pressure
│   ├── environment.json    ← the commands that restore a working state
│   ├── architecture.mermaid← auto-generated dependency diagram
│   └── session_log.jsonl   ← append-only machine log
├── sess_002_auth/          (parent: sess_001)
└── sess_003_payments/      (parent: sess_001, sibling of sess_002)

Sessions form a tree, like branches, because work does. session_tree shows it; session_log is a git log --oneline across all of them.


Requirements

  • Python 3.11+
  • uv for the install script
  • An MCP-capable agent. Built against Claude Code; also usable from Codex (see below)
  • git is optional. Without it the journal records no-git and stays useful

Install

pip install cogsession        # or: uv tool install cogsession
cogsession-admin install

Two commands on purpose. The first installs the MCP server; the second wires the hooks, which is what makes CogSession record without being asked. A package cannot write to ~/.claude/settings.json on its own, so without the second command you get eleven tools you must call by hand and none of the recording.

cogsession-admin install backs up your settings first, adds the six hooks alongside anything already there, and will not overwrite a status line you already set.

Installing from a clone instead (for working on CogSession itself)
git clone https://github.com/premanand8800/cogsession.git
cd cogsession
uv sync
uv run cogsession-admin install --repo .

--repo points the hooks at your checkout through uv, so edits take effect without reinstalling.

The installer syncs dependencies with uv, registers the MCP server with Claude Code, and writes the hooks that let it observe a session without being asked. It touches ~/.claude/settings.json and nothing inside your projects.

It will not write to a file git tracks. The handoff goes to CLAUDE.local.md, which is auto-loaded the same way CLAUDE.md is but never committed. If that filename happens to be tracked in your repo, CogSession refuses to write rather than dirtying your tree, and tells you where the handoff is on disk instead. Add .cogsessions/ to your .gitignore.

The tools

Eleven MCP tools, in four groups:

Group Tools
Lifecycle session_init · session_checkpoint · session_load · session_status
Recording session_update
Searching session_search · session_log · session_tree · session_diagram
Claims claim_record · claim_check

Plus six hooks (SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, PreCompact, SessionEnd) that do the recording you never have to ask for.

What it does not do

Worth saying plainly, because it is the first thing people assume:

CogSession does not store your conversations. It reads the transcript only to measure how full the context window is. What it keeps is conclusions — decisions, dead ends, assumptions, claims — plus the mechanical events from the hooks. That is deliberate: a memory made of every word said is a memory nobody re-reads. But it does mean the quality of a session's memory depends on things being recorded as they are decided.


Usage

Start of every session: nothing. The SessionStart hook opens a session and loads the previous handoff on its own. Tracking that depends on someone remembering to turn it on is tracking that silently does not happen.

Name the session when you know what it is about — the focus line is the only part a tool cannot infer:

session_update(type="focus", content="auth module")

session_init still exists for a session you want to start deliberately, or to attach to a parent:

session_init(project_root="/your/project", focus="auth module")
session_load(project_root="/your/project")   # load a previous handoff by hand

Throughout the session:

session_update(type="decision", content="Use python-jose for JWT", reasoning="Handles RS256 edge cases")
session_update(type="dead_end", content="Using httpx for auth", why_failed="Breaks streaming in /login", use_instead="Use requests library")
session_update(type="assumption", content="users table has hashed_password column", risk_level="HIGH", how_to_verify="Run \\d users in psql")
session_update(type="task_complete", content="Build /register endpoint")
session_update(type="task_add", content="Build /refresh endpoint")
session_update(type="danger_zone", content="Don't touch middleware.py — custom CORS order line 45")
session_status(context_pct=67)

At 70-80% context:

session_checkpoint(context_pct=78, one_liner="Built JWT auth. Refresh token next.")

Look something up without loading anything. Every session keeps a session.md: append-only, one block per event, each header carrying its own local timestamp, event type, and the repo state it happened at (branch@commit+dirty). So one grep answers a question:

grep -n -A4 "dead_end"  .cogsessions/<session>/session.md   # what already failed
grep -n "2026-08-27 01:" .cogsessions/<session>/session.md   # what happened that hour
grep -n "main@a1b2c3d"   .cogsessions/<session>/session.md   # what happened at that commit

Every entry line is self-describing, which is what makes a bare grep useful: a match tells you when, what kind, and against which state of the code, with no need to scroll for context. Tool calls are deliberately left out — hundreds per session would bury the decisions someone is actually searching for; they stay in session_log.jsonl.

Scan history like git log:

session_log()                        # newest first, all sessions
session_log(type_filter="dead_end")  # what has already failed here
when                       what         repo                   session
2026-08-27 01:43:57 +0545  error        master@3d4d1fd+2       sess_20260827_...
2026-08-27 01:43:57 +0545  dead_end     master@3d4d1fd+1       sess_20260827_...

Scan, then grep the journal for the entry that matters. The commit id is the join back to real git log, so a decision can be lined up with the state of the code that produced it.

Claims — for anything you write down that could go stale:

claim_record(
  claim="the composite key includes the tenant column",
  verified_by="grep -c 'UNIQUE (a, b, c)' migrations/007_schema.sql",
  expect="1",
  watches=["migrations/007_schema.sql"],
  asserted_in="PR description, line 26",
)
claim_check()          # re-runs the proofs whose files moved

A claim stores the command that proved it, not a note about how to check it. When the file changes, the next session is told which statements stopped being true, where they were asserted, and how they were checked. Silence means everything still holds.

This exists because the most expensive failure is not a wrong decision. It is a right one that quietly stopped being true — a description of a schema the code no longer has, a comment naming a constraint that moved, a test asserting a shape the implementation dropped.

Explore history:

session_tree(project_root="/your/project")
session_search(project_root="/your/project", query="httpx", type_filter="dead_end")
session_diagram(project_root="/your/project")

How It Works: Inverted Control (Observer-First)

CogSession operates automatically via agent hooks and transcript inspection. You don't need to manually report token percentages or call tools.

  1. Automatic Context Measurement: Context load is read directly from Claude Code session transcripts (input_tokens + cache_creation + cache_read + output_tokens).
  2. Automatic Injection:
    • SessionStart: Injects L0 manifest & L1 handoff unprompted.
    • UserPromptSubmit: Nudges at 65%–74%, recommends at 75%–79%, and mandates checkpoints at $\ge$80%. Surfaces prompt-relevant dead ends and danger zones.
    • PreToolUse: Blocks file edits targeting recorded danger zones.
  3. Deterministic Distillation: Tracks file edits, git operations, commands, and test failures without relying on LLM guesses.

What Makes It Different

Feature Other Systems CogSession
Dead ends tracking ✅ Automatic extraction of failed approaches & reasons
Context load measurement ❌ Guesswork ✅ Ground truth token measurement from transcript
Decision quality flags ✅ Automatically flagged if made at >75% context
Tree structure ❌ linear ✅ Branches like git
Token-aware warnings ✅ Automatic: 65% nudge, 75% alert, 80% mandate
Auto CLAUDE.md handoff ✅ Handoff written automatically at checkpoint
Architecture diagram ✅ Auto-generated Mermaid
Environment snapshot ✅ Exact start commands, ports, env vars

Connect

CogSession is an MCP stdio server. If cogsession is installed in the environment where your agent runs, register it with uv run cogsession.

Codex CLI:

codex mcp add cogsession -- uv run cogsession

If you are running CogSession directly from a local source checkout, point uv at that checkout:

codex mcp add cogsession -- uv --directory /path/to/cogsession run cogsession

Verify the server is registered:

codex mcp list
codex mcp get cogsession

Restart Codex after adding the MCP server. Codex loads MCP tools when a new Codex session starts.

Claude Code:

claude mcp add cogsession -- uv run cogsession

For a local source checkout:

claude mcp add cogsession -- uv --directory /path/to/cogsession run cogsession

Cursor (.cursor/mcp.json):

{"mcpServers": {"cogsession": {"command": "uv", "args": ["run", "cogsession"]}}}

For a local source checkout:

{
  "mcpServers": {
    "cogsession": {
      "command": "uv",
      "args": ["--directory", "/path/to/cogsession", "run", "cogsession"]
    }
  }
}

Disable for a project:

echo '{"enabled": false}' > .cogsession.json

Using CogSession with Codex

CogSession is project-local. It stores session data inside the target project:

/your/project/.cogsessions/

Start Codex from the project you want to remember:

cd /your/project
codex

Then ask Codex to use CogSession in plain language:

load the session and handoff from cogsession

or be explicit:

Use cogsession to load the latest handoff for this project.

If this is the first session for the project:

Use cogsession to initialize a session for this project with focus "initial setup".

During work, record important facts:

Use cogsession to record a decision: "Use the existing service layer for account updates" because "It keeps validation and audit logging in one place".
Use cogsession to record a dead end: "Calling the external API directly from the route handler" because "It bypassed retries and request tracing" and use instead "Call the existing API client wrapper".

Before stopping, checkpoint the session:

Use cogsession to checkpoint this session with context 64% and summary "Implemented account update flow; remaining work is integration tests."

Codex Example

developer@workstation:~/projects/example-app$ codex
╭───────────────────────────────────────────────╮
│ >_ OpenAI Codex (v0.130.0)                    │
│                                               │
│ model:     gpt-5.5   /model to change         │
│ directory: ~/projects/example-app             │
╰───────────────────────────────────────────────╯

› load the session and handoff from cogsession

• Called
  └ cogsession.session_load({
      "project_root": "/home/developer/projects/example-app",
      "load_level": "handoff"
    })

[CogSession] Handoff from sess_20260513_101500_account_updates_a1b2:

# Handoff: sess_20260513_101500_account_updates_a1b2

**Focus:** Account update flow
**Closed:** 64% context | 2026-05-13 23:33
**Parent:** root

## Summary
Account update flow is implemented, validation is wired through the existing
service layer, and lint/type checks are passing. Remaining work is integration
test coverage for error cases.

After loading the handoff, Codex can continue with the saved context:

I implemented the account update flow using the existing service layer:

- Added src/services/account_service.py for update orchestration.
- Updated src/api/account_routes.py to call the service layer.
- Added validation in src/schemas/account.py.
- Documented required environment variables in .env.example.

Verification:
pytest             passed
ruff check .       passed
mypy src           passed

Remaining work:
- Add integration tests for validation failures.
- Confirm production environment variables before release.

Project-Local vs Global

CogSession does not use one global memory store by default. Each project gets its own .cogsessions/ directory.

For this project:

/home/developer/projects/example-app/.cogsessions/

For another project:

/home/developer/projects/admin-tool/.cogsessions/

Those are separate histories. To inspect a specific project, ask Codex:

Use cogsession to show the session tree for /home/developer/projects/example-app.

Codex may show an approval prompt before running a CogSession tool:

Allow the cogsession MCP server to run tool "session_tree"?

1. Allow
2. Allow for this session
3. Always allow
4. Cancel

Choose Allow for this session or Always allow if you want fewer prompts.

Useful Codex Prompts

Use cogsession to load the latest handoff for this project.
Use cogsession to initialize a new session for this project with focus "auth fixes".
Use cogsession to show the session tree for this project.
Use cogsession to search this project for "account update".
Use cogsession to checkpoint this session with context 70% and summary "Implemented auth changes and recorded build blocker."

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cogsession-0.1.0.tar.gz (123.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cogsession-0.1.0-py3-none-any.whl (59.0 kB view details)

Uploaded Python 3

File details

Details for the file cogsession-0.1.0.tar.gz.

File metadata

  • Download URL: cogsession-0.1.0.tar.gz
  • Upload date:
  • Size: 123.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Linux Mint","version":"22.3","id":"zena","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for cogsession-0.1.0.tar.gz
Algorithm Hash digest
SHA256 384b08d5f868ebca01358d6821edea15608c4d1d4a048b95997dd4db13f3adf8
MD5 84022a5f997bff658d4ef64c9de76bf5
BLAKE2b-256 ada49bc1254893bf66aff0302534c6a6639248595618273af6cc259f91911489

See more details on using hashes here.

File details

Details for the file cogsession-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: cogsession-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 59.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Linux Mint","version":"22.3","id":"zena","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for cogsession-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6a8fd67c82a547a3b9e223296afecd72c92efc2fa43fc43165c600723e56599b
MD5 842945968b58777aca95bd477d97102a
BLAKE2b-256 9f47b7454dcbab89c6fad8da6b53732a0b042e480d74f91cac6e1c587f637caf

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page