cc-habits · docs

Getting started

Everything cc-habits does, in roughly the order you'll need it. Start at Install.


Install

cc-habits is a global npm package. You'll need Node 20+ (already installed if you use most AI coding CLIs).

$ npm install -g cc-habits@latest
$ cch init        # cch is short for cc-habits

cch is a short alias for cc-habits. All commands work with either form (cch init, cch view, cch status, etc.).

cch init walks you through provider setup interactively. Pick whichever fits your situation:

ProviderCostSetup
Anthropic API~$0.09 / month (light)console.anthropic.com
Ollama (free, local)$0ollama.com/download
OpenAI APIyour keyplatform.openai.com
Groq APIfree tierconsole.groq.com

No API key? A coding-tool subscription and an AI provider key are billed separately. If you only have a tool subscription, Ollama is the recommended free alternative - it runs locally and needs no API key.

# Quickest path with no API key:
brew install ollama          # or download from ollama.com
ollama pull llama3.2
ollama serve &
cch init --provider ollama

During init, if cc-habits finds past Claude Code sessions for this project, it offers to bootstrap - retroactively learning habits from your existing work:

  Found 4 Claude Code sessions for this project.
  Bootstrap habits from past sessions? [y/N] y

  Extracting patterns...
  ✓ Learned 7 habits across 4 categories from 42 edits

You can re-run this at any time with cch bootstrap.

How it works

cc-habits installs hooks into whichever tools you use, the same way across Claude Code, Gemini CLI, Codex, and Kimi. Each tool uses its own event names, so an --adapter flag (set automatically at install) normalizes every payload into one shape. Run cch tools to see which tools are detected:

PostToolUse (Write|Edit|MultiEdit)
  → captures the diff
  → appends to ~/.cc-habits/log.jsonl
  → exits in ~5ms of work (full hook ~70ms p50, dominated by Node startup)

Stop (session end)
  → reads session signals from log.jsonl
  → one small-model call to extract patterns
  → updates ~/.cc-habits/habits.md
  → prints "cc-habits: learned 2, updated 3."

UserPromptSubmit (every prompt)
  → injects your strongest active habits into context
  → survives context compaction; "laws, not requests"
  → set CC_HABITS_INJECT=0 to disable

SessionStart (session begins)
  → prints "cc-habits: N habits active this session"
  → stays silent when nothing is active

habits.md is also auto-imported into every session via an @import line in your tool's memory file (for example ~/.claude/CLAUDE.md or GEMINI.md), and synced into AGENTS.md and rules files for the rest. The import gives the agent the full picture at session start; the UserPromptSubmit hook re-asserts the top habits on every turn so they don't get summarised away when the context compacts mid-session.

No per-project setup. Hooks live at the user level; habits live in ~/.cc-habits/. cc-habits works globally across every repository you open.

For tools without a hook mechanism (Cursor, Windsurf, Copilot), there is nothing to install: run cch sync and your habits land in their rules files. And for any workflow at all, cch git-capture mines your commit history for patterns; cch init can install a Git post-commit hook so this happens automatically every time you commit.

What it learns

After a few sessions of Claude Code, your habits.md might look like this:

# Coding habits

Auto-generated by cc-habits. Do not edit manually; changes will be overwritten.

## Python

- Add type hints to all function parameters and return types. Confidence: 0.75
  - Signal: 7 reinforcing, 0 contradicting
  - First learned: 2026-05-18
  - Last updated: 2026-05-20

- Use f-strings instead of .format() or string concatenation. Confidence: 0.65
  - Signal: 4 reinforcing, 1 contradicting
  - First learned: 2026-05-18

## Error Handling

- Wrap external I/O in try/except and re-raise as RuntimeError. Confidence: 0.55
  - Signal: 2 reinforcing, 0 contradicting

Your agent reads this file at the start of every session. When it generates code, it already knows your preferences.

Mistake memories

Habits are only half the picture. Habits capture how you prefer code written; memories capture what agents got wrong before, and when that warning is relevant. It is a separate companion to habits with the same plain-text storage, the same graduation gate, and the same tombstones. It is on by default.

$ cch memories              # view what's been remembered
$ cch memories --disable    # turn it off (persists to config.yml)

By default, the session-end pass runs a second extraction that looks for repeated mistakes (the same class of bug you fixed twice) and writes them to ~/.cc-habits/memories.md. Each memory carries a trigger so your agent only sees it when it is about to do that thing again, injected at most a few at a time to stay cheap.

# Coding memories

## Async

- Forgot to await an async call; the promise was used as a value.
  Correction: await the call, or return the promise.
  Trigger: async, await, Promise  ·  Confidence: 0.70

## SQL

- Interpolated a variable straight into a SQL string.
  Correction: use a parameterized query.
  Trigger: query, SQL, execute  ·  Confidence: 0.60

Manage them the same way as habits: cch memories --delete "<text>" tombstones a memory so it is never re-learned, and cch memories --tombstones lists what you have blocked. Disable the whole feature any time with cch memories --disable.

View your habits

$ cch view

  cc-habits · your coding habits

  3 active habits across 2 categories  ·  12 signals processed

  ── Python ──────────────────────────────────────────

  Add type hints to all function parameters and return types
  [███████████████░░░░░░░] 75%  ↑7  ↓0  · since 2026-05-18

  Use f-strings instead of .format()
  [█████████████░░░░░░░░░] 65%  ↑4  ↓1  · since 2026-05-18

  ── Error Handling ──────────────────────────────────

  Wrap external I/O in try/except and re-raise as RuntimeError
  [███████████░░░░░░░░░░░] 55%  ↑2  ↓0  · since 2026-05-19

Status & health

cch status (alias cch doctor) is a one-glance health check: which tools are wired up, whether each one has actually fired its hook (a liveness proof, not just “registered”), your provider, and your habit and signal counts.

$ cch status

  ┌──────────────────────────────────────────────────────────────┐
  │ ✓  Claude Code     live · 2 minutes ago · 546 sigs           │
  │ ~  Cursor          git capture on commit                     │
  │ ✓  Gemini CLI      live · 7 days ago · 1 sig                 │
  │ ✓  Codex CLI       registered (edit in Codex CLI to confirm) │
  │ ✓  Kimi Code CLI   registered (edit in Kimi Code CLI)        │
  ├──────────────────────────────────────────────────────────────┤
  │ provider  ollama (gemma4:31b-cloud)                          │
  │ import    ✓  preferences.md in CLAUDE.md                     │
  │ habits    19 active · 3 learning                             │
  │ signals   1362 total · 5 this session                        │
  │ memory    on                                                 │
  │ version   0.7.12                                             │
  └──────────────────────────────────────────────────────────────┘
  All good. Start a coding session to keep learning.

The “live · N ago” line is logged only when the tool itself runs the hook, so it is a real liveness signal rather than a claim that the config exists. Add --proof to print the exact hook commands written into each tool's config.


The confidence math

Habits are weighted by how consistently you apply them.

EventDelta
New habit created0.50 (in ## Learning, not yet active)
Reinforced in a new session+0.05 (cap 0.95), graduates at 2 sessions
Contradicted−0.10 (−0.20 in a burst of 3+)
Unused for >7 days−0.05 / week decay
Confidence below 0.30pruned

Intentionally simple. Symbolic Bayesian-ish updates with session gating, contradiction velocity, and staleness decay. Honest about the math.

Cost

One small-model call per session. That's it.

With Ollama (free, local): $0 / month - runs entirely on your machine.

With Anthropic Haiku 4.5:

UsageCost / month
Light (1 session / day)~$0.09
Medium (3 sessions / day)~$0.27
Heavy (5+ sessions / day)~$0.60

You provide your own API key. cc-habits does not collect or proxy keys.

Commands

cch init                        # install hooks, choose a provider
cch bootstrap                   # learn habits from past Claude Code sessions
cch learn --repo                # scan this repo with the LLM and learn directly
cch view [habits|memories|prefs] # show current habits, memories, or preferences
cch memories                    # show coding memories (on by default; --disable to turn off)
cch diff [--since N]            # changes since the last write
cch explain "<rule>"            # show signals that produced a habit
cch lint <file> [--json]        # check a source file against your habits
cch export [path]               # print habits.md (or write to path)
cch import <file>               # merge a portable habits file
cch sync [targets] [--dir P]    # write habits to AGENTS.md / Cursor / Cline
cch git-capture [--range r]      # learn from your Git commit history
cch status [--proof]            # health check: hooks, provider, last-fired liveness
cch tools                       # list supported tools and which are detected
cch faq [query]               # search the built-in FAQ, or browse categories
cch on                        # re-enable capture after cch off
cch off                        # pause all capture globally (reversible)
cch migrate                     # migrate storage to ~/.cc-habits/
cch shell-init                  # print a shell wrapper: eval "$(cch shell-init)"
cch uninstall                  # remove all hooks and config
cch tombstone "<rule>"          # block a rule permanently
cch tombstone                   # list tombstoned rules
cch reset --yes                 # wipe habits.md, preferences.md, memories.md, log.jsonl
cch --version                   # print installed version

Safety guarantees

  1. Never fails a coding session. Every hook is wrapped in try/catch. On error: logs to ~/.cc-habits/error.log, exits 0. The || true in the hook command is an extra layer.
  2. No data leaves your machine except the extraction API call. No telemetry, no analytics, no server.
  3. habits.md is human-readable. Read, edit, or delete it at any time. cch reset --yes gives you a clean slate.
  4. Append-only log. Signals in log.jsonl are never modified or deleted except by cch reset.

Privacy

cc-habits is a local-first tool. It is designed so that you are the only data controller for everything it captures.

What is stored, where

Every artifact lives in your home directory. None of these are synced or uploaded by cc-habits.

ArtifactPathMode
Habits file~/.cc-habits/habits.md0600
Signal log~/.cc-habits/log.jsonl0600
Snapshot~/.cc-habits/.snapshot.json0600
Tombstones~/.cc-habits/.tombstones.json0600
Memories~/.cc-habits/memories.md0600
Error log~/.cc-habits/error.log0600
Config (API key)~/.cc-habits/config.yml0600

What leaves the machine

Outbound calls go only to the AI provider you chose: the session-end hook sends a redacted batch of signals for habit extraction. With Ollama, that runs locally and nothing leaves your machine. With a cloud provider it uses your API key, hits the provider directly, and is governed by your agreement with them.

cc-habits does not operate a server. There is no telemetry, no analytics, no error reporting endpoint.

Redaction before any outbound call

Three patterns are replaced with sentinel tokens before signals reach the model:

PatternReplacement
Email addresses (RFC 5322 basic)<REDACTED:email>
Indian PAN (5 letters + 4 digits + 1 letter)<REDACTED:pan>
Credit card numbers (12-19 digits passing Luhn)<REDACTED:card>

The extractor prompt explicitly instructs the model: "Never output content marked <REDACTED:…>."

In addition, extracted rules are sanitized before being written into habits.md: control characters, URLs, zero-width and homoglyph evasions, container-escape tags, and prompt-injection keywords (e.g. "IGNORE PREVIOUS", SYSTEM:) are stripped to prevent a compromised signal from poisoning your agent's context.

If you process other categories of sensitive data (non-Latin PII, custom tokens, healthcare identifiers), audit log.jsonl periodically and consider stricter retention.

You are the data controller

Because everything lives in your home directory and the only outbound call uses your own API key, you are the data controller and data processor under GDPR, DPDP, CCPA, and similar regimes. cc-habits has no privileged access to your data.

If you are operating in a regulated environment:

  • Treat ~/.cc-habits/ as you would any folder containing source-code diffs.
  • Set your provider key (for example ANTHROPIC_API_KEY) via your secrets manager rather than storing it in config.yml.
  • Periodically run cch reset --yes to clear local history. Tombstones survive.
  • For air-gapped contexts, do not run cch init. Without an API key, the Stop hook fails closed.

Recommended hygiene

  • Do not sync ~/.cc-habits/ via Dropbox, iCloud, Syncthing, or similar. Diffs of your code travelling between machines materially expands the data-loss surface. Add it to your sync tool's ignore list.
  • Move your API key to a secrets manager. Storing it in config.yml is convenient but co-resident processes can read it. Setting ANTHROPIC_API_KEY via your shell profile + a secrets agent is stronger.
  • Audit log.jsonl if you handle sensitive data. It contains 30+ days of code diffs by default. Consider periodic rotation.

What cc-habits will never do

  • It will not phone home. There is no cc-habits server.
  • It will not modify code in your repositories. It only writes to ~/.cc-habits/ and your tools' own config files.
  • It will not register itself with any tool without cch init running explicitly.
  • It will not fail a coding session. Every hook is wrapped in try/catch and exits 0 on error.

Reporting a privacy concern

If you believe cc-habits has leaked data or has a vulnerability with privacy impact, please report it via a GitHub security advisory rather than a public issue: github.com/Shreyan1/cc-habits/security/advisories/new.

cc-habits · spec

habits-format v0.3

Status: Draft v0.3 · Editor: Shreyan Basu Ray · License: CC-BY 4.0 · Reference: cc-habits

A portable, human-readable schema for representing a developer's learned coding habits. Designed so any tool - not just cc-habits - can read, write, and exchange habits files.

This document is the normative specification. Where the reference implementation and this document disagree, this document governs the on-disk format and the implementation is the bug.

1. Design goals

  1. Human-readable. Anyone can cat the file and understand it.
  2. Markdown-native. It IS markdown. No second parser needed for rendering.
  3. Idempotent round-trip. Parsing and re-serialising must preserve all semantic content.
  4. Editor-friendly. A user can manually edit, delete, or reorder rules without breaking tools.
  5. Tool-portable. cc-habits is one valid renderer; nothing in the spec depends on its internals.

2. File structure

A habits file is a single UTF-8 markdown document with these sections, in order:

1. Format version comment      (REQUIRED)
2. Document title              (REQUIRED)
3. Edit-policy note            (RECOMMENDED)
4. Zero or more category sections   (## <CategoryName>)
5. Zero or one Learning section     (## Learning (not yet active))

2.1 Format version comment

The first non-empty line MUST be an HTML comment of the form:

<!-- cc-habits format v0.3 -->

Readers MUST refuse to parse files whose major version they do not implement. Older minor versions SHOULD be parsed best-effort (v0.x minor versions are additive).

2.2 Document title

The document title MUST be exactly:

# Coding habits

2.3 Edit-policy note

A single paragraph explaining the file's behaviour. Recommended text:

Auto-generated by cc-habits. You may edit this file; rules you delete will not be recreated.

2.4 Category section

## <CategoryName>

- <Rule text>. Confidence: <0.00-1.00>
  - Signal: <int> reinforcing, <int> contradicting
  - Sessions seen: <int>
  - Languages: <comma-separated list>     [OPTIONAL]
  - First learned: <YYYY-MM-DD>            [OPTIONAL]
  - Last updated: <YYYY-MM-DD>             [OPTIONAL]

Rule text is a single declarative sentence. The trailing period before Confidence: is REQUIRED. Confidence is a decimal between 0.00 and 1.00 with two decimal places.

2.5 Learning section

## Learning (not yet active)

> These habits have been observed in only one session. They are
> quarantined here until reinforced in a second distinct session.
> Claude should not apply rules in this section.

- [<CategoryName>] <Rule text>. Confidence: <0.00-1.00>
  - Signal: ...
  - Sessions seen: 1
  ...

Learning rules carry their owning category in [brackets]. Once observed in a second distinct session, the writer MUST move the rule out of Learning into its category section.

3. Semantics

3.1 Sessions seen

Sessions seen: N is the count of distinct work sessions in which this rule has been observed. It is the canonical promotion gate:

  • Sessions seen: 1 → Learning section, NOT applied
  • Sessions seen ≥ 2 → category section, applied

3.2 Confidence

Confidence is updated by the writer according to its own model. The reference cc-habits implementation uses:

  • New rule: start at 0.50
  • Reinforcing signal: +0.05 (cap 0.95)
  • Contradicting signal: −0.10 (−0.20 when 3+ in the same batch)
  • Decay: −0.05 per week unused after a 7-day grace period
  • Prune: rules below 0.30 are removed

Other implementations MAY use different update rules. The on-disk number is the source of truth.

3.3 Languages & dates

Languages: ts, py, go is an optional set of file extensions in which this habit was observed. First learned and Last updated are ISO-8601 UTC dates.

4. Companion files

Implementations MAY produce companion files alongside the habits file. They are NOT part of the portable format. A tool that doesn't recognise a companion file MUST leave it untouched.

FilePurpose
.tombstones.jsonRules the user has manually deleted
.snapshot.jsonLast-written state, used to detect manual deletes
.history.jsonlAppend-only log of past habits.md contents
.provenance.jsonMap of rule → contributing signals
.memory-tombstones.jsonMemories the user has manually blocked

5. Tombstones

A tombstone is a single normalised rule string. Format:

[
  "use strict mode",
  "prefer async await over promise chains"
]

Normalisation: trim whitespace, strip trailing period, lowercase. When a writer receives a create decision for a rule whose normalised form matches an entry in tombstones, it MUST skip the create.

6. Compatibility & versioning

  • Files MUST declare their format version in the leading HTML comment.
  • A reader encountering an unknown minor version MAY proceed but SHOULD warn.
  • A reader encountering an unknown major version MUST refuse to parse.

This spec is v0.3. Minor versions are additive and backward-compatible. Breaking changes will bump the major version.

7. Reference grammar (informal)

File           = VersionComment Title EditPolicy? CategoryBlock* LearningBlock?
VersionComment = "<!-- cc-habits format v0.3 -->"
Title          = "# Coding habits"
CategoryBlock  = "## " CategoryName HabitEntry*
LearningBlock  = "## Learning (not yet active)" BlockQuote LearningEntry*
HabitEntry     = "- " RuleText ". Confidence: " Confidence Newline MetaLine*
LearningEntry  = "- [" CategoryName "] " RuleText ". Confidence: " Confidence Newline MetaLine*
MetaLine       = SignalLine | SessionsLine | LanguagesLine | FirstLearnedLine | LastUpdatedLine

This specification is licensed CC-BY 4.0. You may build commercial or open-source tools that implement it without attribution beyond a link to this document. The reference implementation is separately licensed MIT.

edit on github