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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ docs/AUDIT-PROMPT.md
docs/ARCHITECTURE.md
docs/ROADMAP.md
docs/TOOL-AUDIT.md
docs/LOOP-ENGINEERING.md
docs/VERIFICATION.md
docs/VISION-CHECKLIST.md

# Internal launch/marketing working files — never publish
marketing/
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Adherence gate: close-the-loop writes (`knitbrain_record_learning`, `knitbrain_s
**High-fanout (change carefully):** `src/ccr/store.ts`, `src/tokenizer.ts`, `src/engine/feedback.ts`, `src/engine/memory.ts`, `src/engine/knowledge.ts` — check `knitbrain_query_dependents` before touching.
**Largest:** `src/mcp/tools.ts`, `scripts/production-audit.mjs`, `src/learn.ts`

Full architecture map + audit procedure: `docs/AUDIT-PROMPT.md`.
System design (processes, state, flows, failure domains): `docs/ARCHITECTURE.md` · Binding product map (gaps, kill-list, UX law, build order, platform ledger): `docs/LOOP-ENGINEERING.md` (both internal, gitignored).

---

Expand Down
212 changes: 125 additions & 87 deletions README.md

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "knitbrain",
"version": "0.17.0",
"description": "Local-first MCP brain for coding agents: code retrieval, lossless context compression, persistent per-project memory, and a verify-gated closed loop — for Claude Code, Cursor, Copilot, and any MCP client.",
"description": "Loop engineering substrate for coding agents — state, lossless optimization, and hook enforcement: verify-gated loops that can't lie, run away, or go broke. For Claude Code, Codex, Cursor, Gemini CLI, VS Code Copilot, and any MCP client.",
"type": "module",
"main": "dist/lib.js",
"types": "dist/lib.d.ts",
Expand Down Expand Up @@ -30,6 +30,12 @@
"knowledge-graph",
"code-search",
"retrieval",
"loop-engineering",
"agent-loop",
"hooks",
"enforcement",
"codex",
"gemini-cli",
"token-optimization",
"context-engineering",
"prompt-compression",
Expand Down
2 changes: 1 addition & 1 deletion scripts/bench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { activeTokenizerName } from "../src/tokenizer.js";
import { measure, summarize, type Measurement } from "../src/measure.js";
import { measure, summarize, type Measurement } from "./measure.js";
import { createFileCCRStore } from "../src/ccr/store.js";
import { compressJson } from "../src/optimizer/json.js";
import { compressCode } from "../src/optimizer/code.js";
Expand Down
2 changes: 1 addition & 1 deletion src/measure.ts → scripts/measure.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { countTokens } from "./tokenizer.js";
import { countTokens } from "../src/tokenizer.js";

/** Result of measuring a single original→optimized payload pair. */
export interface Measurement {
Expand Down
20 changes: 0 additions & 20 deletions scripts/research-measure.mjs

This file was deleted.

134 changes: 0 additions & 134 deletions scripts/research.mjs

This file was deleted.

125 changes: 0 additions & 125 deletions scripts/shape-profile.mjs

This file was deleted.

16 changes: 16 additions & 0 deletions src/engine/receipt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,22 @@ export function buildReceipt(i: ReceiptInput): string {
}
}

// G3 cold-restart waste: the sink optimization can't touch. The provider's
// prompt cache expires after ~5min idle — every gap >5min in the session's
// event stream means the NEXT turn re-read the whole context uncached.
// Estimated from event timestamps (labeled estimate; skipped when unknowable).
if (mark && events.length >= 2) {
const CACHE_TTL_MS = 5 * 60_000;
const ts = events.map((e) => Date.parse(e.ts)).filter((t) => Number.isFinite(t)).sort((a, b) => a - b);
let coldGaps = 0;
for (let j = 1; j < ts.length; j += 1) if (ts[j]! - ts[j - 1]! > CACHE_TTL_MS) coldGaps += 1;
if (coldGaps > 0 && meter.usedTokens > 0) {
lines.push(
`${coldGaps} idle gap(s) >5min — each next turn re-read ~${fmtTokens(meter.usedTokens)} tok uncached (estimate); a handoff + fresh session is cheaper than a cold return`,
);
}
}

lines.push(`lifetime: ${fmtTokens(meter.savedTokens)} tok saved · ${retrievalsTotal} exact recalls`);

if (eventsTrimmed) {
Expand Down
4 changes: 4 additions & 0 deletions src/fan.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// KEEP ruling (kill-list note): the "own worktree manager" kill targets a
// worktree SERVICE. fan does not manage worktrees as a product surface — it
// uses git's own `git worktree` per parallel task, exactly the coordination
// the loop-engineering doc endorses. fan is the parallelism leg of the loop.
import { spawn, spawnSync } from "node:child_process";
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
Expand Down
6 changes: 1 addition & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { VERSION } from "./version.js";
const KNOWN_COMMANDS = new Set([
"version", "-v", "--version", "help", "-h", "--help",
"setup", "hub", "join", "profile", "wrap", "prompt", "statusline",
"terse", "evals", "compress", "loop", "fan", "orchestrate", "learn",
"terse", "evals", "compress", "loop", "fan", "learn",
"onboard", "dashboard",
]);

Expand Down Expand Up @@ -142,10 +142,6 @@ usage: knitbrain <command>
const { runFan } = await import("./fan.js");
process.exit(await runFan(process.argv.slice(3)));
}
if (process.argv[2] === "orchestrate") {
const { runOrchestrate } = await import("./orchestrate.js");
process.exit(runOrchestrate(process.argv.slice(3)));
}
if (process.argv[2] === "learn") {
const { runLearn } = await import("./learn.js");
await runLearn(process.argv.slice(3));
Expand Down
Loading
Loading