Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,68 @@ All notable changes to fs-cortex will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [4.5.0] — 2026-07-05

**Installer reliability.** A sandboxed 6-agent audit ran the installer against
three scenarios — fresh install, upgrade over realistic v3.37 data, v4 refresh
— and confirmed two real data-loss bugs plus a Windows corruption set. All
fixed; the v3-data migration path came back clean (v4 code self-heals legacy
formats lazily) and is now documented. Implementation: Codex (spec-driven),
verified inline.

### Security
- `install.ps1`: the backup-archive path-traversal guard regex was
over-escaped in a single-quoted string and never matched `../` entries —
fixed to match install.sh's semantics (`(^/|\.\.)`), validated at prompt
time with `tar -tzf` like the bash installer.

### Fixed
- **`install.sh`/`install.ps1`: CLAUDE.md user content after the Cortex
section was deleted on every rerun** (confirmed twice in the audit — the
section-replace regex swallowed to the next heading OR EOF). The section
now ships with a `<!-- cortex:end -->` marker and the replace stops there;
legacy sections without the marker anchor on the known final section line
and never swallow to EOF (explicit warn if neither matches).
- **`install.sh`/`install.ps1`: a user hook sharing a settings.json handler
entry with a cortex hook was silently dropped** — the merge now filters at
hook level and only drops entries left empty.
- `install.sh`: interrupted installs (hooks copied, no `version` file) hit a
silent legacy branch that bypassed the downgrade guard — now warned as
"proceeding as repair"; Step 11 (CLAUDE.md) failures no longer abort the
run under `set -e`, so the version marker is always reached.
- `install.sh` Step 8b deployed the STALE `githooks/pre-push` (75 lines)
instead of `.githooks/pre-push` (149 lines, the real hook used via
`core.hooksPath`) — fixed and the stale directory removed.
- `install.ps1` (Windows corruption set): embedded Python now opens
CLAUDE.md/JSON with explicit UTF-8 (locale cp1252 mojibaked every
multibyte char); settings hooks written with the DETECTED interpreter
(`python` vs hardcoded `python3` — hooks never ran on stock Windows
Python); backup import semantics matched to install.sh (memory/reflexes
OVERWRITE from backup — was dead code; registry/instincts/evolved/daily
no-clobber — was `-Force`; `evolved/` now `-Recurse`); `$LASTEXITCODE`
checked after every native call (settings-merge failure no longer prints
success); `.repo-path` written so the deploy-drift guard works on Windows;
JSON migrations atomic (temp + `Move-Item`); memory version floor no
longer rewinds 2-part versions (`'4.0'` → 3.12.0 bug).
- `install.sh`: `reflexes.json` migration writes atomically (tmp + rename).

### Added
- **v3→v4 adapter** in both installers: upgrading from < 4 seeds
`.last-learn-count` from the existing observation count, so the
SessionStart observations banner counts since-upgrade instead of the
entire v3 history.
- `docs/MIGRATION-V4.md` §"Automatic v3-data adaptation (v4.5.0)": what
self-heals, what resets by design, what needs action (CORTEX_DEBUG for
silently-skipped hollow YAMLs, 30d TTL on legacy pending proposals,
v3-era cron jobs on deprecated commands are no-ops).
- `core/memory.template.json` version 3.12.0 → 4.0.0 (release rule §2b).

### Tests
- `test_install` 42→49 (user tail survives rerun, mixed-entry user hook
survives, v3 upgrade seeds marker, repair warning), `test_install_ps1`
10→18 (interpreter, traversal regex, `.repo-path`, UTF-8, import
semantics, marker contract — runs on windows-latest CI).

## [4.4.0] — 2026-07-05

**`/cx-curate` — the semantic curator.** Automates the judgment `/cx-downvote`
Expand Down
1 change: 1 addition & 0 deletions core/claudemd-section.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ Cortex observes sessions and distills knowledge in 3 levels:

### Data: ~/.claude/cortex/
### Laws inject automatically. Instincts inject per tool use. No action needed.
<!-- cortex:end -->
2 changes: 1 addition & 1 deletion core/memory.template.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "3.12.0",
"version": "4.0.0",
"config": {
"max_observations_mb": 10,
"archive_days": 30,
Expand Down
15 changes: 12 additions & 3 deletions docs/FEATURES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# fs-cortex v4.4.0 — Feature Reference
# fs-cortex v4.5.0 — Feature Reference

> Complete inventory of all features, commands, hooks, modules, and capabilities.
> Last updated: 2026-07-05
Expand Down Expand Up @@ -367,6 +367,14 @@ Deterministic rules via hooks — not probabilistic instructions. Triggers are r
- **Bash** (macOS/Linux): `bash install.sh`
- **PowerShell** (Windows): `powershell -ExecutionPolicy Bypass -File install.ps1`

### Reliability (v4.5.0 — sandboxed audit of fresh/v3-upgrade/v4-refresh)
- **CLAUDE.md section replace is loss-proof**: the section ships with a `<!-- cortex:end -->` marker and the replace stops there; legacy sections (no marker) anchor on the known final line and NEVER swallow to EOF — user content after the section survives every rerun (previously deleted, confirmed bug)
- **settings.json merge filters at hook level**: a user hook sharing a handler entry with a cortex hook survives (previously the whole entry was dropped)
- **Interrupted installs self-identify**: hooks dir present without `version` file → "proceeding as repair" warning instead of the silent legacy branch that bypassed the downgrade guard; Step 11 failures no longer abort mid-run
- **v3→v4 adapter**: upgrading from < 4 seeds `.last-learn-count` from the existing observation count (kills the lifetime-count banner); full adaptation notes in `docs/MIGRATION-V4.md`
- **Windows parity + corruption fixes** (install.ps1): explicit UTF-8 in every embedded Python (no more cp1252 mojibake of CLAUDE.md), hooks written with the DETECTED interpreter (`python` vs `python3`), backup import overwrite/no-clobber semantics matched to install.sh (+ `evolved/` recursed), path-traversal regex actually rejects `../`, `$LASTEXITCODE` checked after every native call, `.repo-path` written (deploy-drift guard now works on Windows), atomic JSON migrations
- `reflexes.json` migration writes atomically (tmp + rename); pre-push hook installs from `.githooks/` (the stale `githooks/` copy is gone)

### Smart Upgrade
- Version detection via `~/.claude/cortex/version`
- Shows upgrade path (e.g., "v3.0.0 → v3.6.0")
Expand Down Expand Up @@ -417,7 +425,7 @@ Deterministic rules via hooks — not probabilistic instructions. Triggers are r
| `test_session_learner.sh` | 61 | Error-fix pairs, corrections, chains, proposals, command timeline; **v3.36.1**: semantic fix summary, hollow-fix skip, writeProposals quality gate; **v3.37.0**: err_msg required, input-derived trigger validation, project scope, evidence samples, agent-pattern scoped trigger; **v3.37.1**: rejection tombstones; **v3.37.2**: isError guards + WebFetch 200-OK no-proposal e2e; **v4.0.0**: draft/confirmed lifecycle; **v4.3.0**: `cx-maintain-ttl` accepted as tombstone rejecter |
| `test_injector.sh` | 29 | Sanitization, ReDoS, limits, markers, yaml-utils, .last-instinct, engine; **v3.36.1 e2e**: category domain injects with detected stack, hollow action never injects; **v3.37.0 e2e**: per-session repeat cooldown (max 2 + suppress events), token-budget degrade keeps highest-confidence, concurrent-injector count integrity |
| `test_yaml_utils.sh` | 16 | Floats, ints, strings, colon values, update, list; **v3.36.1**: literal/folded/last-field block scalars |
| `test_install.sh` | 42 | Fresh install, upgrade, idempotency, **strict** path traversal (no fake-green), **v3.19.0 env merge** (CORTEX_AGENT_DISABLE_REFLEXES added, user vars preserved, idempotency, opt-out respected) |
| `test_install.sh` | 49 | Fresh install, upgrade, idempotency, **strict** path traversal (no fake-green), **v3.19.0 env merge** (CORTEX_AGENT_DISABLE_REFLEXES added, user vars preserved, idempotency, opt-out respected); **v4.5.0**: user tail after CLAUDE.md section survives rerun (marker), user hook sharing entry with cortex hook survives merge, v3 upgrade seeds `.last-learn-count`, interrupted install → "proceeding as repair" |
| `test_hooks_e2e.sh` | 14 | Full pipeline: observe→inject→learn, **token budget reset** |
| `test_uninstall.sh` | 13 | Cleanup, backup creation, data preservation, **safety guard**, CLAUDE.md preservation, **v3.19.0 env removal** (Cortex var removed, user vars preserved, empty env block dropped) |
| `test_integrity.sh` | 14 | observe.py direct, **21 commands** validated (EXPECTED_COMMANDS subset; 24 command files total as of v4.0.0 — `ls commands/*.md` — incl. new `cx-maintain`/`cx-review` not yet in EXPECTED_COMMANDS), core file schemas, **version consistency** |
Expand All @@ -426,7 +434,7 @@ Deterministic rules via hooks — not probabilistic instructions. Triggers are r
| `test_curate.sh` | 6 | **(v4.4.0)** `apply_confidence_downvote` (reduce+log, 0.30 floor, unknown id), `curate_snapshot()` shape on seeded sandbox, `curate_due()`/`touch_curate_marker()` gating, `curate-snapshot` CLI prints valid JSON |
| `test_injector_v4.sh` | 13 | **(v4.0.0)** `status: draft` never injects, `status: confirmed`/legacy-no-field inject normally, subtopic dedup + domain soft-ceiling at conf>=0.85, JSON-fragment + prompt-injection action guards, degenerate-trigger static validation, live `reflexes.json` polling conditions |
| `test_cx_maintain_runner.sh` | 10 | **(v4.0.0, inventoried v4.2.2)** `bin/cx-maintain.sh` hermetic sandbox: exit 0 on repeated runs, decay exactly-once (same-day idempotency via `last_decay_at`), compat markers, valid `.review-digest.json`, no leftover lock dir, `--dry-run` writes nothing; **v4.2.2**: learn markers reset (`.last-learn-count` snapshot, `.obs-count` zeroed, `.learn-pending` cleared); **v4.3.0**: engine-pass report carries `swapped=`/`expired=` counters |
| `test_install_ps1.ps1` | 10 | PowerShell syntax, version consistency, security features, backup categories, hook config, v3.26-v3.28 source files present, **CI on windows-latest** |
| `test_install_ps1.ps1` | 18 | PowerShell syntax, version consistency, security features, backup categories, hook config, v3.26-v3.28 source files present, **CI on windows-latest**; **v4.5.0**: detected-interpreter hooks (no hardcoded python3), traversal regex rejects `../`, `.repo-path` write, UTF-8 in embedded Python, backup overwrite/no-clobber semantics, `<!-- cortex:end -->` marker contract |
| `test_impact.sh` | 32 | **Sprint 0/1 funnel** — schema v1, JS↔Python compat, concurrent writes (10 parallel → 0 loss), rotation, gate GO/NO-GO, formulas, input validation, **v3.17.0 source split** (user/agent ratios, gate input, legacy default), **v3.18.0 auto-eval** (3 evaluator types, no-evaluator default, reflex iid prefix) |
| `test_cross_day_tracker.sh` | 10 | Roundtrip, boost tiers (1/2/4/8 days), confidence cap 0.95, Jaccard match, single-token guard, prune >365d, concurrent append |
| `test_detectors_v327.sh` | 12 | detectAgentSubtypes (emit/no-emit/rate), detectFileCoupling (emit/no-emit/missing-path, `::` in paths), detectTimeOfDayPatterns (buckets, empty, merge, reflect JSON structure, corrupted-file no-clobber) |
Expand Down Expand Up @@ -672,6 +680,7 @@ locally (not installed to `~/.claude/`):
| v4.0.0 | 2026-07-02 | **"Signal-first, zero-decision" — full redesign of capture and command set.** `docs/DESIGN-V4.md` + `docs/SPEC-PORT-SINAPSIS.md` (port of Sinapsis v4.6.1, MIT, Luis Salgado). **BREAKING:** 17 of 24 commands deprecated to notice-only stubs (mapping in `docs/MIGRATION-V4.md`); 7 remain active (`cx-status`, `cx-maintain`, `cx-review`, `cx-eod`, `cx-gotcha`, `cx-backup`, `cx-restore`). New `/cx-maintain` (deterministic, cron-able: decay+purge+auto-validate+deterministic law-promotion+Jaccard dedup-by-subtopic+storage rotation+proposals↔instincts reconciliation+health check, writes `.review-digest.json`). New `/cx-review` (the only command with human judgment, weekly, fuses old validate+evolve-confirm+downvote+distill-swap into one shorthand pass). `hooks/observe.py`: per-line capture guards before trusting an error match (`[codex]`/npm-log prefixes, version listings, grep headers, `0 errors`, bare `warning:`), `output` cap 8000→10000, `err_msg` now the first non-guarded matching line. New `status: draft`/`confirmed` instinct lifecycle (`session-learner.js`, `injector-engine.js`) — drafts track silently, auto-promote at `occurrences>=5 AND sessions_seen>=3`; legacy instincts default `confirmed`. Law promotion gate replaced with a fully deterministic one (`conf>=0.95`, `projects_seen>=3`, `occurrences_v4>=10` via lazy `occurrences_legacy` migration, 0 noise 14d) — `auto-distill-candidates.md` buzón removed. Injector: JSON-fragment + prompt-injection guards at load, degenerate-trigger static validation, dedup switched from per-domain to per-subtopic (2 first words of id) with a soft 2-per-domain ceiling at conf>=0.85. `core/_cx-eod-gather.sh`: per-project `context` field, `[eod-eisenhower]` Q1-Q4 keyword classification of "for tomorrow" bullets, review-digest pending count surfaced. New test suites `test_distill_v4.sh` (6/6 PASS), `test_injector_v4.sh` (13/13 PASS). |
| v4.1.0 | 2026-07-04 | **Audit hardening (multi-agent audit + adversarial verify).** `session-start.py` injects full law text (not just line 1). `session-learner.js`: tombstone gate matches by trigger vs `proposals-history.jsonl`, dup-trigger dedup, `$HOME`→`~` paths, head+tail sampling. Reflexes: re-enabled `python3-bypass-write-tool`, hardened `bash-cat-use-read`. `storage-rotation.js`: prunes `cross-day-tracker` past 1.5× threshold, stale `.lock`/`.bak` cleanup, `timeline.jsonl` rotation. `distill_engine.py`: `prune_instinct_tracking()` + `reap_stale_nudge_state()` + CLI subcommands. `injector-engine.js`: session token budget 8000→12000 with a visible suppression warning, optional per-reflex `domains` filter. |
| v4.2.0 | 2026-07-05 | **Laws layer: de-dup, tier legibility, post-promotion audit** (`docs/DESIGN-laws-v4.2.md`; 3-agent adversarial pass). Fixed double injection (`read-instructions` 41×, `pref-fix` 17× redundant PreToolUse) — `injector-engine.js` skips instinct candidates with a `laws/{id}.txt` twin; `manual_swap_promote` archives the source instinct like `auto_promote_to_law`. `advisor-escalation` trimmed 1505→717 chars. Reverted the v4.1.0 `bash-cat-use-read` lookahead regression (broke `test_reflex_matchers`). Added law presentation split by tier (`[principios]`/`[herramienta]`, `core/laws-meta.default.json`) + `law_audit()` + `law-audit` CLI. |
| v4.5.0 | 2026-07-05 | **Installer reliability — sandboxed audit of fresh install, v3-data migration and v4 refresh (6-agent workflow + Codex implementation).** Confirmed data-loss bugs fixed: CLAUDE.md user content after the Cortex section deleted on every rerun (now marker-bounded `<!-- cortex:end -->` + legacy anchor, never swallows to EOF); user hook sharing a settings entry with a cortex hook dropped (now hook-level filter). Half-install hardening: Step 11 failures no longer abort; missing version file → "proceeding as repair" instead of silently bypassing the downgrade guard. v3→v4 adapter seeds `.last-learn-count`; `docs/MIGRATION-V4.md` documents self-heals / by-design resets / action-needed. Windows: UTF-8 everywhere (cp1252 mojibake fix), detected-interpreter hooks, backup import semantics matched to sh (+ evolved/ recursed), traversal regex fixed, `$LASTEXITCODE` checked, `.repo-path` (drift guard live on Windows), atomic migrations. Stale `githooks/` removed (pre-push installs from `.githooks/`). `core/memory.template.json` → 4.0.0. `test_install` 42→49 (audit had found the table stale at 42 vs 44 real), `test_install_ps1` 10→18. |
| v4.4.0 | 2026-07-05 | **`/cx-curate` — semantic curator; `/cx-downvote` judgment automated.** The LLM half of zero-touch: Claude classifies laws (generality, redundancy vs CLAUDE.md/skills, value-per-token), demotes niche laws via the v4.3.1 cascade, promotes only trigger-less knowledge, downvotes broken instincts (`apply_confidence_downvote`, floor 0.30). Weekly `.last-curate` cadence; `[CURATE] due` banner auto-triggers execution. Engine: `curate_snapshot()` + CLI `curate-snapshot`/`downvote`, `curate_due()`/`touch_curate_marker()`, `CURATE_*` constants. Born validated: a 29-agent semantic audit recomposed the live constitution the same day (6 laws demoted to instincts; 0 promotions — every top candidate already lived as a 0.99 trigger-gated instinct, a finding folded into the PROMOTE criterion; 10 broken instincts downvoted; cap 15/15 → 9/15). Implemented by 3 parallel subagents + integration verifier. `test_curate` new 6, `test_session_start` 11→14. Active commands 7→8; `core/claudemd-section.md` refreshed to the v4 set (stale since v4.0.0). |
| v4.3.1 | 2026-07-05 | **Retired laws cascade to instincts (operator feedback on v4.3.0).** Auto-swap retirement and `demote_law_to_domain` share `_restore_backing_instinct()`: the victim's backing YAML returns to `instincts/global/` with `law_eligible: false` (no re-promotion ping-pong), keeping the knowledge injecting via PreToolUse and subject to normal decay. Fixes the two-layer loss (promotion archives the instinct; retirement used to archive the law → knowledge gone from both). Also fixes `demote_law_to_domain`'s lookup, blind to the `<id>.promoted-to-law-<date>.yaml` name every v4 promotion writes. No-backing laws stay archive-only (never invent a trigger). `test_distill_v4` 10→12. |
| v4.3.0 | 2026-07-05 | **Zero-touch mode — the pipeline never waits on a human.** Reverts the v4.2 "human prunes" model at the operator's request. (1) `auto_promote_to_law` auto-swaps at a saturated cap: victim = `_find_least_impactful_law` (lowest useful/(1+noise) 14d), age >= 30d (`LAW_AUTO_SWAP_MIN_AGE_DAYS`), max 2 swaps/run, only when the cap is the sole failing gate; executes via `_swap_promote_unlocked` (extracted from `manual_swap_promote` — calling the locked wrapper from inside the maintain lock would deadlock on the shared flock). (2) `expire_stale_proposals()`: pending human-gated proposals older than 30d (`PROPOSAL_TTL_DAYS`) auto-reject as `cx-maintain-ttl` (added to both tombstone whitelists — never resurrect). (3) SessionStart badge informative: `[cx] maintain: +law (jubilada X), N caducadas, M en cola` from digest `swaps_last_run`/`expired_last_run`, silenced 48h after the pass; the imperative `[REVIEW] N items -> /cx-review` badge is gone. (4) `/cx-review` reframed as optional veto pass. Shared `_archive_promoted_instinct_source` helper dedups 3 archive sites. `test_distill_v4` 6→10, `test_session_start` 7→11, `test_session_learner` 60→61, runner report carries `swapped=`/`expired=`. Implementation delegated to Codex GPT-5.3 (spec-driven), reviewed inline. |
Expand Down
Loading
Loading