Skip to content
Open
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
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Changelog

## v4.5.0 (2026-04-18) — unreleased

### Added — Laws tier (inspired by fs-cortex, credit: Fernando Montero / MIT)
- **`core/_laws-injector.sh`** (new SessionStart hook): emits `SESSION_PREFETCH_LAWS:` lines from `~/.claude/skills/_laws/*.txt`. Max 10 laws per session, cap ~300 tokens (conservative 4 chars/token). Rotates by `last_injected` ASC for variety across sessions. Atomic write (tmp → rename) survives concurrent sessions.
- **`seeds/laws/*.txt`** (5 ported seeds, MIT © Fernando Montero): `read-first`, `grep-read-verify`, `git-triple-check`, `never-hardcode-secrets`, `three-layer-security`.
- **`seeds/laws/README.md`**: schema + attribution.
- **Law model**: `Law = one-line projection of a permanent instinct (or stand-alone seed)`. `source_instinct: null` → stand-alone. `/promote --law` distills a permanent instinct into a Law (see `commands/promote.md` Step 4).
- **10 TDD tests** (`tests/test-laws.sh`): presence, seed count, empty-dir silent exit, emission format, MAX_LAWS cap, `last_injected` atomic update, rotation ordering, malformed-file resilience, whitespace normalization. 10/10 GREEN.

### Changed
- `install.sh`: copies `_laws-injector.sh` + seed laws into `~/.claude/skills/_laws/` (idempotent; existing files preserve their `last_injected`).
- `core/settings.template.json`: adds `SessionStart` hooks section (`_hooks_total`: 6 → 7, `_hooks_breakdown`: `SessionStart(1) + PreToolUse(4) + PostToolUse(1) + Stop(1)`).
- `commands/promote.md`: adds Step 4 "Offer Law Distillation" — when an instinct is promoted to `permanent`, user can accept a suggested one-liner to write into `_laws/`.

### Rationale
Sinapsis already projected patterns as instincts (regex-gated, per-tool-use injection). What was missing: a thin tier of **always-on crystallized wisdom** — the 5-10 principles the user never wants to risk forgetting, no matter the context. Matches fs-cortex's `laws` concept without replacing instincts: laws are a *projection* of permanents, not a parallel registry. Existing commands (`/promote`, `/evolve`) keep working unchanged; the hook is purely additive at the end of the SessionStart array.

### Test badge
116 → 126 passing (suite-wide, 8 test files).

---

## v4.4.1 (2026-04-17)

### Fixed
Expand Down
31 changes: 30 additions & 1 deletion commands/promote.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,43 @@ PROMOTE TO PERMANENT
1. Update `level` from `confirmed` to `permanent` in `_instincts-index.json`
2. Preserve all other fields (trigger_pattern, inject, domain, origin, added)

### Step 4: Summary
### Step 4: Offer Law Distillation (v4.5+)

For each freshly promoted instinct, ask whether to distill a `Law` — a one-liner projection injected at SessionStart via `_laws-injector.sh`. Laws are cheaper than instincts (no regex match, always injected) and best suited for universal principles the user never wants to forget.

```
git-commit-conventional is now permanent.
Distill as Law? (always injected at SessionStart, ~300 token budget)

Suggested: "Use conventional commits (feat/fix/chore/docs/refactor). Subject <=72 chars."
Edit? [Enter to accept, type replacement, or [S] skip]
```

On accept, write to `~/.claude/skills/_laws/<instinct_id>.txt`:

```
---
id: <instinct_id>
source_instinct: <instinct_id>
source: /promote
created: <today>
last_injected: 1970-01-01T00:00:00Z
---
<one-liner text, <=40 tokens>
```

Heuristic for suggested text: take `instinct.inject`, trim to one clause, keep <=40 tokens. If user types replacement, use verbatim.

### Step 5: Summary

```
PROMOTION COMPLETE

2 instincts promoted to permanent.
1 distilled as Law.
Permanent: 1 → 3
Confirmed: 3 → 1
Laws: 5 → 6

These instincts now have highest priority in domain dedup.
```
93 changes: 93 additions & 0 deletions core/_laws-injector.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/bin/bash
# Sinapsis v4.5 — Laws Injector (SessionStart hook)
#
# Always-injected one-liner tier: crystallized wisdom projected from permanent
# instincts (or fs-cortex seed stand-alones). Max 10 laws per session, cap ~300
# tokens, rotation by last_injected ASC for variety across sessions.
#
# Inspired by fs-cortex laws tier — credit: Fernando Montero (MIT, 2026).
#
# Model:
# permanent instinct (full entry in _instincts-index.json)
# |
# v optionally distilled via /promote --law
# Law (one-liner in _laws/<id>.txt, injected at SessionStart)

LAWS_DIR="$HOME/.claude/skills/_laws"

[ ! -d "$LAWS_DIR" ] && exit 0

if [ "${SINAPSIS_DEBUG:-}" = "1" ]; then
exec 2>>"$HOME/.claude/skills/_sinapsis-debug.log"
fi

node -e '
const fs = require("fs");
const path = require("path");

const LAWS_DIR = process.env.HOME + "/.claude/skills/_laws";
const MAX_LAWS = 10;
const TOKEN_BUDGET = 300; // conservative cap; Claude-style estimate ~4 chars/token
const CHARS_PER_TOKEN = 4;

function parseLaw(filePath) {
const content = fs.readFileSync(filePath, "utf8");
const m = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
if (!m) return null;
const fm = {};
for (const line of m[1].split(/\r?\n/)) {
const kv = line.match(/^([\w-]+):\s*(.*)$/);
if (kv) fm[kv[1]] = kv[2].trim();
}
const text = m[2].trim().replace(/\s+/g, " ");
if (!fm.id || !text) return null;
return Object.assign(fm, { text, filePath });
}

let files;
try {
files = fs.readdirSync(LAWS_DIR).filter(f => f.endsWith(".txt"));
} catch(e) { process.exit(0); }
if (!files.length) process.exit(0);

const laws = [];
for (const f of files) {
try {
const law = parseLaw(path.join(LAWS_DIR, f));
if (law) laws.push(law);
} catch(e) { /* skip malformed */ }
}
if (!laws.length) process.exit(0);

// Rotation: oldest last_injected first → round-robin variety over sessions.
laws.sort((a, b) => (a.last_injected || "").localeCompare(b.last_injected || ""));

const selected = [];
let tokenCount = 0;
for (const law of laws) {
if (selected.length >= MAX_LAWS) break;
const lawTokens = Math.ceil(law.text.length / CHARS_PER_TOKEN);
if (tokenCount + lawTokens > TOKEN_BUDGET) break;
selected.push(law);
tokenCount += lawTokens;
}
if (!selected.length) process.exit(0);

for (const law of selected) {
process.stdout.write("SESSION_PREFETCH_LAWS: " + law.text + "\n");
}

// Atomic last_injected update (write tmp → rename). Survives concurrent sessions.
const now = new Date().toISOString();
for (const law of selected) {
try {
const content = fs.readFileSync(law.filePath, "utf8");
const updated = content.replace(/^(last_injected:\s*).*$/m, "$1" + now);
const tmp = law.filePath + ".tmp";
fs.writeFileSync(tmp, updated);
fs.renameSync(tmp, law.filePath);
} catch(e) { /* best-effort; next session retries */ }
}
' 2>/dev/null

exit 0
19 changes: 16 additions & 3 deletions core/settings.template.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
{
"_comment": "Sinapsis v4.1 — settings.json template. Copy to ~/.claude/settings.json (merge with existing).",
"_hooks_total": 6,
"_hooks_breakdown": "PreToolUse(4) + PostToolUse(1) + Stop(1)",
"_comment": "Sinapsis v4.5 — settings.json template. Copy to ~/.claude/settings.json (merge with existing).",
"_hooks_total": 7,
"_hooks_breakdown": "SessionStart(1) + PreToolUse(4) + PostToolUse(1) + Stop(1)",
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"_comment": "laws-injector: emits SESSION_PREFETCH_LAWS lines (max 10, cap ~300 tokens, rotation)",
"type": "command",
"command": "bash ~/.claude/skills/_laws-injector.sh",
"timeout": 3
}
]
}
],
"PreToolUse": [
{
"matcher": "*",
Expand Down
13 changes: 9 additions & 4 deletions docs/FEATURES.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Sinapsis v4.3.3 — Feature Reference
# Sinapsis v4.5 — Feature Reference

> Complete inventory of all features, commands, hooks, modules, and capabilities.
> **Update this file with every feat/fix commit.**
> Last updated: 2026-04-13
> Last updated: 2026-04-18

---

Expand Down Expand Up @@ -31,20 +31,25 @@ Parallel systems (not part of the confidence pipeline):

| Injection Point | What | When | Tokens |
|---|---|---|---|
| **SessionStart** | Project context.md + EOD resume | Once per session (via _project-context.sh) | ~150 |
| **SessionStart** | Project context.md + EOD resume + **Laws (v4.5)** | Once per session | ~150 + ~300 laws |
| **PreToolUse** | Instincts (max 3) + Passive Rules (max 3) | Every tool use (if trigger matches) | ~200 max |

### 6-Hook Pipeline
### 7-Hook Pipeline

| Hook | File | Lines | Event | Mode | Timeout |
|---|---|---|---|---|---|
| **Laws Injector (v4.5)** | `_laws-injector.sh` | 70 | SessionStart | Sync | 3s |
| Observer | `observe_v3.py` | 200 | Pre/PostToolUse | Async (0 tokens) | 10s |
| Project Context | `_project-context.sh` | 136 | PreToolUse | Sync (1x/session) | 3s |
| Passive Activator | `_passive-activator.sh` | 66 | PreToolUse | Sync | 5s |
| Instinct Activator | `_instinct-activator.sh` | 221 | PreToolUse | Sync | 5s |
| Observer (post) | `observe_v3.py` | — | PostToolUse | Async | 10s |
| Session Learner | `_session-learner.sh` | 329 | Stop | Sync | 15s |

### Laws tier (v4.5)

Always-injected one-liner projections of permanent instincts (or stand-alone seeds). Rotated by `last_injected` ASC, capped at 10 laws / ~300 tokens per session. 5 seeds ship from fs-cortex (MIT © Fernando Montero): `read-first`, `grep-read-verify`, `git-triple-check`, `never-hardcode-secrets`, `three-layer-security`. New laws distilled via `/promote --law` after an instinct is promoted to `permanent`.

---

## Hooks (7 files)
Expand Down
18 changes: 17 additions & 1 deletion install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -166,16 +166,32 @@ cp "$SCRIPT_DIR/core/_eod-gather.sh" "$SKILLS_DIR/_eod-gather.sh"
cp "$SCRIPT_DIR/core/_dream.sh" "$SKILLS_DIR/_dream.sh"
cp "$SCRIPT_DIR/core/_generate-dashboard.py" "$SKILLS_DIR/_generate-dashboard.py"
cp "$SCRIPT_DIR/core/_dashboard-template.html" "$SKILLS_DIR/_dashboard-template.html"
cp "$SCRIPT_DIR/core/_laws-injector.sh" "$SKILLS_DIR/_laws-injector.sh"

chmod +x "$SKILLS_DIR/_passive-activator.sh"
chmod +x "$SKILLS_DIR/_instinct-activator.sh"
chmod +x "$SKILLS_DIR/_session-learner.sh"
chmod +x "$SKILLS_DIR/_project-context.sh"
chmod +x "$SKILLS_DIR/_eod-gather.sh"
chmod +x "$SKILLS_DIR/_dream.sh"
chmod +x "$SKILLS_DIR/_laws-injector.sh"
chmod +x "$SKILLS_DIR/_generate-dashboard.py" 2>/dev/null || true

echo -e "${GREEN} OK${NC} 5 hook scripts + dream cycle + dashboard generator installed"
# ── Step 5c: Ship-with-install seed laws (v4.5) ──
# Copy seed laws to ~/.claude/skills/_laws/. Idempotent: existing files preserved
# (last_injected timestamps survive upgrades).
if [ -d "$SCRIPT_DIR/seeds/laws" ]; then
mkdir -p "$SKILLS_DIR/_laws"
for lawfile in "$SCRIPT_DIR/seeds/laws"/*.txt; do
[ -f "$lawfile" ] || continue
lawname=$(basename "$lawfile")
if [ ! -f "$SKILLS_DIR/_laws/$lawname" ]; then
cp "$lawfile" "$SKILLS_DIR/_laws/$lawname"
fi
done
fi

echo -e "${GREEN} OK${NC} 6 hook scripts + dream cycle + dashboard generator + laws injector installed"

# ── Step 5b: Legacy file cleanup (v4.3.3) ──
LEGACY_CLEANED=0
Expand Down
29 changes: 29 additions & 0 deletions seeds/laws/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Seed laws

One-liner crystallized wisdom. Shipped with install, copied to `~/.claude/skills/_laws/`, injected at SessionStart by `_laws-injector.sh` (max 10, cap ~300 tokens, rotation by `last_injected`).

## Schema

```
---
id: <kebab-case-id>
source_instinct: <instinct_id | null>
source: <origin tag>
license: <MIT or omit>
created: <YYYY-MM-DD>
last_injected: <ISO-8601 | 1970-01-01T00:00:00Z>
---
<one-line text, <=40 tokens>
```

`source_instinct: null` = stand-alone seed with no instinct counterpart. When `/promote --law` distills a permanent instinct, `source_instinct` points to that instinct id.

## Seeds shipped

All 5 ported from [fermontero/fs-cortex](https://github.com/fermonterom/fs-cortex) (MIT © 2026 Fernando Montero):

- read-first
- grep-read-verify
- git-triple-check
- never-hardcode-secrets
- three-layer-security
9 changes: 9 additions & 0 deletions seeds/laws/git-triple-check.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
id: git-triple-check
source_instinct: null
source: seed:fermontero-fs-cortex
license: MIT
created: 2026-04-18
last_injected: 1970-01-01T00:00:00Z
---
Before any git commit: run git status + git diff + git log to triple-check changes.
9 changes: 9 additions & 0 deletions seeds/laws/grep-read-verify.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
id: grep-read-verify
source_instinct: null
source: seed:fermontero-fs-cortex
license: MIT
created: 2026-04-18
last_injected: 1970-01-01T00:00:00Z
---
Always Grep -> Read -> Verify before editing any file. Never edit blind.
9 changes: 9 additions & 0 deletions seeds/laws/never-hardcode-secrets.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
id: never-hardcode-secrets
source_instinct: null
source: seed:fermontero-fs-cortex
license: MIT
created: 2026-04-18
last_injected: 1970-01-01T00:00:00Z
---
NEVER hardcode secrets, API keys, or tokens. Always use environment variables.
9 changes: 9 additions & 0 deletions seeds/laws/read-first.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
id: read-first
source_instinct: null
source: seed:fermontero-fs-cortex
license: MIT
created: 2026-04-18
last_injected: 1970-01-01T00:00:00Z
---
Always read documentation and instructions before executing any skill or command.
9 changes: 9 additions & 0 deletions seeds/laws/three-layer-security.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
id: three-layer-security
source_instinct: null
source: seed:fermontero-fs-cortex
license: MIT
created: 2026-04-18
last_injected: 1970-01-01T00:00:00Z
---
Enforce 3-layer security: middleware auth -> API route validation -> Supabase RLS.
Loading
Loading