Metadata-Version: 2.4
Name: codemind-ci
Version: 0.2.0
Summary: CodeMind — gives your repo a memory that catches contradictions on PRs
Author-email: Kajal Jotwani <kajaljotwani06@gmail.com>
License-Expression: MIT
Project-URL: Repository, https://github.com/kajal-jotwani/Hangover
Project-URL: Issues, https://github.com/kajal-jotwani/Hangover/issues
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Software Development :: Version Control :: Git
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click>=8.1
Requires-Dist: cognee>=1.0.0
Requires-Dist: openai>=1.50.0
Requires-Dist: pydantic>=2.0
Requires-Dist: gitpython>=3.1
Requires-Dist: rich>=13.0
Requires-Dist: python-dotenv>=1.0
Requires-Dist: requests>=2.31
Provides-Extra: dev
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Requires-Dist: pytest; extra == "dev"
Dynamic: license-file

# CodeMind — The Repo That Remembers

**Your repo has opinions. Watch it catch a teammate breaking one — live.**

CodeMind is a persistent memory graph for a codebase that doesn't just store facts
about *why* the code is the way it is — it watches new commits, detects when they
contradict an established decision, and forces a reconciliation moment: confirm the
change is intentional (memory revises itself) or catch a regression before it ships.

> This isn't a linter. It's memory that can be **wrong**, get **challenged**, and
> **correct itself** — the way a real teammate's understanding would.

Built on **Cognee Cloud** for the wemaekdev hackathon.

---

## The problem

Every team loses tribal knowledge constantly. A new hire "cleans up" code that looks
redundant. It wasn't redundant. It ships. It breaks in prod. Static tools (linters,
code-review bots, RAG-over-docs) only see the code *as it is right now* — they have no
memory of *why* it got that way, and no mechanism to notice when someone unknowingly
undoes a hard-won decision. Existing "repo assistant" tools read a repo once and
summarize a **snapshot**. CodeMind's bet: the valuable thing isn't remembering the code,
it's remembering the **decisions** — and noticing when new code violates them.

---

## How the Cognee lifecycle maps to CodeMind

| Cognee primitive | What it does in CodeMind | Where it fires |
|---|---|---|
| `remember()` | Extracts a structured "decision fact" from a commit (what / why / scope / confidence) and stores it in the shared graph | `ingest.py` |
| `recall()` | Retrieves relevant past decisions when a new diff touches related code | `contradiction.py` (hybrid retrieval) |
| `improve()` | Re-weights the graph after a human confirms a contradiction is an **intentional** update — the old belief is revised, not just appended | `reconcile.py confirm` |
| `forget()` | Surgically retires the single superseded memory by `data_id` (not the whole dataset) — the old belief is visibly crossed out | `reconcile.py confirm` |

> **Why Cloud specifically:** if the memory graph lived on one laptop it wouldn't be
> team memory — it'd be personal notes. The graph has to be **shared and consistent
> across every contributor and every CI run** for it to reflect team-wide, ongoing
> consensus. That requires Cognee Cloud, not a self-hosted single instance.

---

## 🧠 Cognee operations callout (for "Best Use of Cognee" judges)

All four lifecycle verbs are used **meaningfully and live**, plus the deeper
`cognee.search` graph-node retrieval, and the GitHub commit-status + issue
integrations:

- **`cognee.serve(url, api_key)`** — routes every op to the shared Cloud tenant (`config.py`); tenant/user headers patched into the session (`cognee_client._inject_headers`).
- **`cognee.remember(text, dataset_name, importance_weight, self_improvement=True)`** — each extracted decision is stored with an importance score; `self_improvement` auto-runs `improve` (`cognee_client.remember_decision`, called from `ingest.py` and `reconcile.py`). The new item's `data_id` is isolated by **diffing the items list before/after** (the list isn't in insertion order).
- **`cognee.recall(query_text, datasets, top_k, auto_route)`** — semantic retrieval over the graph (`cognee_client.recall_decisions`).
- **`cognee.search(query_text, datasets, only_context=True, feedback_influence=…, neighborhood_depth=…, include_references=True)`** — pulls the **actual graph nodes** (Decision + Rationale + keyword tags), deeper than `recall`'s LLM answer. Used in `contradiction.py` to cite the specific node a diff contradicts, and in the dashboard to render the live graph (`cognee_client.search_graph_nodes`). `feedback_influence` is wired so the reconcile `confirm`/`reject` signal can shape future retrieval.
- **`cognee.forget(data_id, dataset)`** — **surgical single-memory deletion** by `data_id` (confirmed working on cloud). This is what makes "old belief crossed out" honest rather than faked (`cognee_client.forget_one` / `forget_many`).
- **`cognee.improve(dataset_name)`** — explicit re-weight after an update (`cognee_client.improve_graph`, best-effort — see note below). Auto-runs via `remember(self_improvement=True)`.

> **Honest caveat:** `cognee.memify()` and `cognee.visualize()` are blocked on
> this cloud tenant — `memify` 404s (`Empty graph projected`) + 422 (`LLM API key
> not set`), and `visualize`/`datasets.list_datasets` crash on a broken local-SQLite
> path in cloud mode. So `improve` stays best-effort and the dashboard renders the
> live graph from `cognee.search(only_context=True)` nodes instead of `visualize()`.
> The feedback-re-weight loop (`cognee.add_feedback` → `memify` applies the weights)
> is likewise blocked on cloud: `add_feedback` isn't exposed on the cloud client and
> the local session manager no-ops (returns `False`) in cloud mode; `recall` surfaces
> no qa/session ids to feedback on. The "memory learns from human feedback" thesis
> is instead embodied by the **confirm/reject** loop — `confirm` revises the belief
> (`remember` UPDATE + surgical `forget` + `improve`), `reject` holds it. Every
> Cognee API the tenant *does* support is leaned on; the ones it blocks are
> documented rather than faked.

### Integrations (the rules: "and integrations")
- **GitHub PR comments** — the conflict posts as a real comment citing the violated decision + Cognee graph evidence (`github.post_or_print`).
- **GitHub commit-status check** — green on clean PRs, **red** on conflict (lights up the PR check summary); `reconcile confirm` flips red → green, `reject` keeps it red (`github.post_commit_status`). Usable as a **required** status check so a contradictory PR can't merge.
- **GitHub issue on reject** — `reconcile reject` auto-opens an issue tracking the caught regression, labeled `codemind` + `regression` (`github.create_issue`).
- **CI on every PR** — two GitHub Actions workflows (`.github/workflows/`) run detection + the comment-triggered reconcile loop (see "CI — runs on every PR" below).
- **Auto-ingest on merge** — a third workflow (`codemind-ingest.yml`, opt-in via `vars.CODEMIND_AUTO_INGEST=true`) runs `ingest.py --since $before --head $after` on every push to `main`, so the graph grows itself with the team's merged history — "no action needed, just learning."

## 🌐 Cross-repo shared memory (the Cloud-native differentiator)

The Cognee Cloud graph is **tenant-global**: a decision remembered in repo A is
retrievable from repo B's CI run. That's not a caveat here — it's the headline.
It's the whole reason Cloud (not self-hosted) matters: **one memory graph across
your whole org's repos**. A hard-won decision made in the payments repo protects a
PR in the checkout repo. No local/self-hosted memory can do this.

**Already proven live:** PR #6 ran with `local signals: 0` (no committed
`memory_registry.json` on that branch) and the shared Cloud graph still surfaced
**12 graph nodes** + the correct verdict via `cognee.search(only_context=True)` —
i.e. the run's only memory was the graph populated by other repos' ingests. The
dashboard pulls **16 live nodes** from the same shared graph.

**Proven locally too (read-only):** with the local registry blanked (simulating
repo B's no-registry state), `python -m codemind.runtime.contradiction --repo demo_repo --branch violation --no-post`
still returns `conflict: True` citing *"Cache layer must be Redis"* — `local signals: 0`,
`semantic recall: 1`, `graph nodes: 11`, all from the shared Cloud graph. The catch
comes entirely from memory another repo populated.

**Full two-repo theatrical demo** (a second repo wired to the same tenant catches a
Redis→Map PR citing a decision remembered in repo A):
```bash
gh repo create <you>/codemind-cross-b --private        # you create repo B (one step)
bash scripts/setup_cross_repo.sh <you>/codemind-cross-b # pushes code, sets secrets, opens the violation PR
```
The script gives repo B NO `memory_registry.json`, so its only memory is the shared
Cloud graph. Within ~2 min the CodeMind bot comments on repo B's PR citing
*"Cache layer must be Redis"* — a decision remembered in repo A — and a red
`CodeMind / memory` check appears. That's org-wide shared memory, live.

The reconciliation moment — `remember` the update → `forget` the old belief → `improve`
re-weights → re-`recall`/`search` shows the changed answer — is the entire thesis, and it runs live.

---

## Why this is different

Repo Guardian / CodeBase Navigator / Beetle AI / Congming / CodeSage all read a repo
**once** and summarize/analyze it (a snapshot). **CodeMind is the only entry making a
claim about belief over time** — the memory can be wrong, get corrected, and visibly
change its mind. The contradiction moment is the demo, not "codebase assistant."

---

## Architecture

```
demo_repo (git)  ──▶  ingest.py  ──▶  cognee.remember()  ──▶  Cognee Cloud graph
                       (LLM extracts                       (dataset: codemind_repo_memory)
                        decision facts)                              │
                                                                       │ recall()
                                                                       ▼
new diff  ──▶  contradiction.py  ──▶  hybrid retrieval  ──▶  LLM judge  ──▶  conflict
               (semantic recall +          (Ollama Cloud)            │
                path-scope + keyword                                  ▼
                overlap unioned)                              github.post_or_print
                                                                 │
                                                          ┌──────┴───────┐
                                                          ▼              ▼
                                                   confirm (intentional)  reject (bug)
                                                   remember UPDATE         no memory change
                                                   forget old (data_id)    ← caught a real mistake
                                                   improve()
                                                          │
                                                          ▼
                                                   re-call() → answer CHANGED  (the proof)
```

**Local state:** `memory_registry.json` maps each decision to its Cognee `data_id` so
`forget` can target a single memory. `event_log.json` is the append-only "belief changed"
timeline (feeds the dashboard).

### Files
- `config.py` — env, constants, Cognee connection helper
- `cognee_client.py` — async wrapper over the Cognee SDK (captures `data_id` at remember-time)
- `llm.py` — local LLM (Ollama, OpenAI-compatible) calls: `extract_decision()` + `judge_contradiction()` (JSON-structured)
- `git_io.py` — read commits/diffs/branch-diffs via the git CLI
- `registry.py` — local registry + event log + hybrid-retrieval helpers
- `ingest.py` — Phase 1: walk history → extract → remember → registry
- `contradiction.py` — Phase 2: 3-signal retrieval → judge → surface conflict
- `reconcile.py` — Phase 3: `confirm` (remember+forget+improve) / `reject` (no change)
- `github.py` — optional real PR comment if `GH_TOKEN` set, else terminal+file
- `spike.py` — Phase 0 de-risk: confirms surgical `forget` works before building on it
- `scripts/seed_demo_repo.sh` — builds demo_repo with 4 seeded decisions + violation/benign branches
- `scripts/setup.sh` — one-time pre-demo prep (seed + ingest + recall check)
- `scripts/run_demo.sh` — the scripted 2-minute walkthrough
- `codemind dashboard` — STRETCH: renders the memory graph + belief-changed timeline to HTML; pulls **live Cognee graph nodes** via `cognee.search(only_context=True)` and shows the Cognee lifecycle-API footprint
- `codemind doctor --cognee` — live spike of the deeper Cognee APIs (`search`, `visualize`, `memify`, `datasets`) against the cloud tenant; documents which work vs. are blocked

---

## Setup

### Primary path
```bash
pip install codemind-ci        # from PyPI
codemind init
```

For local development from this checkout:
```bash
python3.13 -m venv .venv && .venv/bin/pip install -e .
codemind init
```

`codemind init` detects the git repo, validates the Cognee + Ollama credentials, writes `.env`, copies the GitHub Actions workflows, sets GitHub secrets when `gh` is available, stores a retention policy, and runs the first bounded ingest.

### Manual / advanced setup
```bash
cp .env.example .env
# Cognee Cloud:  COGNEE_URL (tenant API Base URL), COGNEE_API_KEY (X-Api-Key),
#               COGNEE_TENANT_ID (X-Tenant-Id), COGNEE_USER_ID (X-User-Id)
# Ollama Cloud: OLLAMA_API_KEY (https://ollama.com/settings/keys), OLLAMA_MODEL
# (optional: GH_TOKEN, GH_REPO, GH_PR_NUMBER for real PR comments)
```

### Phase 0 spike
```bash
.venv/bin/python -m codemind.runtime.spike
# expect: remembered 2 -> forgot 1 -> 1 remains. Confirms surgical forget() works.
```

### Prep the demo
```bash
bash scripts/setup.sh
# rebuilds demo_repo, ingests 4 decisions into Cognee, confirms the 'before' recall
# returns the clean answer ("no, must use Redis"). Re-runnable.
```

---

## The demo (2 minutes)

```bash
bash scripts/run_demo.sh   # press ENTER to advance each beat
```

| Time | Beat |
|---|---|
| 0:00–0:20 | The problem: teams lose why-code-is-the-way-it-is. CodeMind gives the repo a memory that argues back. |
| 0:20–0:40 | Show the seeded graph; `recall("can I use an in-memory Map cache instead of Redis?")` → the **old** answer ("no, must use Redis — Mar 2 stale-config incident"). Remember it. |
| 0:40–1:10 | Live commit: a teammate replaces Redis with a per-process in-memory `Map`. `contradiction.py` fires and posts the conflict citing the cache decision. |
| 1:10–1:30 | `reconcile confirm` → `remember` the UPDATE, `forget` the old belief (surgical, by `data_id`), `improve` re-weights. Old belief visibly crossed out. |
| 1:30–1:50 | `recall("can I use an in-memory Map cache instead of Redis?")` again → the answer has **changed** ("yes, superseded as of the update"). The before/after flip is the loop closing. |
| 1:50–2:00 | Close: memory that can be wrong, get challenged, and correct itself. |

### Manual control (for testing)
```bash
.venv/bin/python -m codemind.runtime.contradiction --repo demo_repo --branch violation   # should flag the Redis decision
.venv/bin/python -m codemind.runtime.contradiction --repo demo_repo --branch benign      # should stay quiet (same-file refactor)
.venv/bin/python -m codemind.runtime.reconcile confirm --reason "intentional, rationale updated"
.venv/bin/python -m codemind.runtime.reconcile reject
.venv/bin/codemind dashboard && open dashboard/index.html        # stretch visual
```

---

## Verification (end-to-end)

1. `python -m codemind.runtime.spike` → remember 2, forget 1, 1 remains. (Phase 0 gate — surgical forget works.)
2. `bash scripts/setup.sh` → rebuilds demo_repo, ingests 4 decisions; the pre-demo recall returns the clean **before** answer ("no, must use Redis"). Re-runnable: `--reset` surgically forgets every registry `data_id` (including any prior UPDATE) so the graph is clean each run.
3. `python -m codemind.runtime.contradiction --branch violation` → conflict citing the Redis decision; `--branch benign` (a same-file `DEFAULT_TTL` refactor) → no conflict. **Both must hold.**
4. `python -m codemind.runtime.reconcile confirm` → `event_log.json` gains remember+forget+improve; the contrastive recall now returns the **updated** belief ("yes, superseded"), different from step 2. (Proof the loop closed.)
5. `python -m codemind.runtime.reconcile reject` → registry unchanged; recall answer unchanged. (Bug-caught branch verified.)
6. `bash scripts/run_demo.sh` → full walkthrough runs clean.
7. **CI (every PR):** push the repo (with committed `memory_registry.json` + `.github/workflows/`) to GitHub, add the Cognee/Ollama secrets, open a PR with the Redis→Map change → `github-actions[bot]` posts the CodeMind conflict comment citing the cache decision; push another commit → **no duplicate** (idempotency); reply `/codemind confirm intentional, single-instance deploy` → after-recall comment shows the answer flipped ("superseded as of the update"); open a second PR with a different change → a fresh comment on that PR's number (proves it works on **all** PRs).
8. **Green/red check:** a clean PR → `CodeMind / memory` → `success` ("No contradiction with past decisions"); a conflicting PR → `failure`. Both verified live (PRs #4 red, #6 green on this repo).
9. **Auto-ingest (dry-run):** `python -m codemind.runtime.ingest --repo . --since <sha> --head <sha> --dry-run` → extracts decisions from the range and prints them, **without** calling `remember()`. Verified locally. The live `codemind-ingest.yml` runs the same in `--since`/`--head` mode on push to main (opt-in via `vars.CODEMIND_AUTO_INGEST=true`).
10. **Cross-repo shared memory:** `bash scripts/setup_cross_repo.sh <you>/codemind-cross-b` → repo B (no local registry) catches a Redis→Map PR citing a decision remembered in repo A, via the shared Cloud graph. Mechanism already proven live: PR #6 ran with `local signals: 0` and the shared graph surfaced 12 nodes + the correct verdict.
11. **Unit tests:** `.venv/bin/python -m unittest discover -s tests` → 11 tests covering the registry fuzzy-match (reconcile's data_id lookup), the hybrid-retrieval keyword/path signals, and the GitHub comment idempotency marker + graph-evidence formatting. (The fuzzy-match test caught a real punctuation bug — `Redis;` wasn't matching `redis` — now fixed.)

### CI demo (the live loop, ~90s — for the recording)
The terminal demo above is the thesis; this is the product running in real CI. Live artifacts on this repo to show on camera:
1. **PR #4** (https://github.com/kajal-jotwani/Hangover/pull/4) — a teammate's Redis→Map PR. Show the bot comment with the **Graph evidence** block (cites the actual Cognee node *"Cache layer must be Redis"*) and the **red `CodeMind / memory` check** in the PR summary.
2. **PR #6** (https://github.com/kajal-jotwani/Hangover/pull/6) — a clean PR. Show the **green `CodeMind / memory` check** ("No contradiction with past decisions"). Same check, green vs red.
3. **Dashboard** — `codemind dashboard` → the live Cognee memory graph (16 nodes), the lifecycle-footprint badges, the belief-changed timeline. A static snapshot is pushed to the `gh-pages` branch; enable GitHub Pages (Settings → Pages → Source: `gh-pages`) to get a live linkable dashboard at `https://<owner>.github.io/<repo>/`.
4. **Cross-repo (optional closer):** `bash scripts/setup_cross_repo.sh <you>/codemind-cross-b` → repo B catches the same mistake using a decision remembered in repo A — org-wide memory.
5. **Reconcile (optional):** reply `/codemind confirm intentional, single-instance deploy` on PR #4 → the check flips red→green + an after-recall comment shows the answer changed. *(Mutates the demo graph — run `bash scripts/setup.sh` after to reset.)*

---

## Why this scores on the rubric ("Best Use of Cognee")

The rubric: *"must use Cognee for memory; the more deeply you lean on its lifecycle APIs (remember, recall, improve/memify, forget) and integrations, the stronger you score."* CodeMind's alignment, honestly:

- **All four lifecycle verbs, live:** `remember` (ingest + auto-ingest on merge + reconcile's UPDATE), `recall` (hybrid retrieval in every CI run), `forget` (surgical by `data_id` on confirm — verified working on cloud), `improve` (best-effort on cloud; auto-runs via `self_improvement=True`).
- **Deeper than the verbs:** `cognee.search(only_context=True)` pulls the actual graph nodes, cited as **Graph evidence** in PR comments and rendered in the dashboard — the deepest retrieval the tenant supports.
- **Integrations (4):** PR comments, commit-status check (green/red, blocks merge when required), auto-issue on reject, and CI on every PR via two Actions workflows (+ auto-ingest on merge).
- **Cloud-native, not Cloud-optional:** cross-repo **shared** memory across the whole org — the one thing self-hosted memory structurally cannot do. The graph is tenant-global by design; CodeMind turns that into the product.
- **Honest where the tenant is limited:** `memify`/`visualize`/`datasets.*`/`add_feedback` are blocked on this cloud tenant — documented with the exact errors, not faked. The dashboard renders the graph from `search(only_context=True)` nodes; the "learns from feedback" thesis is carried by the confirm/reject loop.

---

## Tech stack
- **Memory:** Cognee Cloud (shared graph across contributors/CI — the whole point)
- **LLM (extraction + judgment):** Ollama Cloud via its OpenAI-compatible endpoint (`https://ollama.com/v1`, Bearer key; e.g. `gpt-oss:120b`). Cognee Cloud runs its own LLM for graph ingestion server-side, so the two are independent.
- **Ingestion:** Python + git CLI reading `git log -p` and branch diffs
- **Integration:** GitHub PR comments via GitHub API (env-gated; terminal fallback by default)
- **Dashboard:** static HTML generated from local state (stretch)

## Cut list (if behind, in order)
dashboard → real GitHub PR comments (fall back to terminal) → second demo scenario → anything beyond the one scripted contradiction. **Never cut the reconciliation loop — it's the thesis.**

---

## CI — runs on every PR (GitHub Actions)

The terminal demo is one thing; the real product runs in CI on **every pull request**,
not a hardcoded PR number. Two workflows live in `.github/workflows/`:

- **`codemind-pr.yml`** — triggers on `pull_request` (opened / synchronize / reopened).
  Checks out the PR head, recalls relevant past decisions from the Cognee Cloud graph,
  judges whether the diff contradicts any of them, and posts a real PR comment when it
  does. Idempotent per head SHA (pushing another commit to the same PR does *not* spam a
  duplicate).
- **`codemind-reconcile.yml`** — triggers on an `issue_comment` starting with
  `/codemind `. Re-derives the conflict from the PR diff (no duplicate comment), runs the
  reconcile loop, and posts the **after-recall** result as a new PR comment — the
  loop-closing beat, automated.

```
PR opened ── codemind-pr.yml ──▶ contradiction.py ──▶ PR comment (⚠️ conflict) ──▶ author/maintainer replies
                                                                                  │
                                /codemind confirm <reason>   OR   /codemind reject
                                                                                  ▼
                       codemind-reconcile.yml ──▶ reconcile.py confirm|reject --ci ──▶ PR comment (✅/⛔ after-recall)
```

### Required repo secrets (Settings → Secrets → Actions)
`COGNEE_URL`, `COGNEE_API_KEY`, `COGNEE_TENANT_ID`, `COGNEE_USER_ID`, `OLLAMA_API_KEY`
(and optional `COGNEE_DATASET`, `OLLAMA_MODEL` to override defaults). `GITHUB_TOKEN` is
auto-provided by Actions and posts comments as `github-actions[bot]`. To post under a
human identity instead, add a `GH_PAT` secret (classic PAT with `repo` scope, or
fine-grained with *Issues: write* + *Pull requests: write*). Both paths use the same
workflow — `GH_TOKEN: ${{ secrets.GH_PAT || secrets.GITHUB_TOKEN }}`.

### Memory convention
Run `bash scripts/setup.sh` (or `ingest.py`) once locally to build the Cloud graph, then
**commit `memory_registry.json`** to the repo so CI has the local decision manifest for
the path-scope + keyword retrieval signals. If the registry is absent, detection
gracefully degrades to semantic-recall-only (no crash). Re-running ingest later refreshes
the graph; the committed registry keeps the local signals in sync.

### Commands (reply to the CodeMind conflict comment)
- `/codemind confirm <reason>` — the change is intentional: old belief crossed out
  (`forget`), `UPDATE` remembered, `improve()` re-weights, after-recall posted.
- `/codemind reject` — the change is a bug: memory unchanged, old belief reaffirmed.
