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
90 changes: 90 additions & 0 deletions .codex/hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "knitbrain-hook sessionstart"
}
]
}
],
"UserPromptSubmit": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "knitbrain-hook userpromptsubmit"
}
]
}
],
"PreToolUse": [
{
"matcher": "Read",
"hooks": [
{
"type": "command",
"command": "knitbrain-hook pretooluse"
}
]
}
],
"PostToolUse": [
{
"matcher": "Bash|Grep|Glob|WebFetch|WebSearch",
"hooks": [
{
"type": "command",
"command": "knitbrain-hook posttooluse"
}
]
}
],
"PreCompact": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "knitbrain-hook precompact"
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "knitbrain-hook stop"
}
]
}
],
"SubagentStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "knitbrain-hook subagentstart"
}
]
}
],
"SubagentStop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "knitbrain-hook subagentstop"
}
]
}
]
}
12 changes: 12 additions & 0 deletions .gemini/commands/goal.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
description = "Drive a goal to a verify gate WITH YOU in this session (in-chat orchestration)"
prompt = """
Drive the goal in the arguments to done WITH YOU in THIS session (single context). The verify gate is the truth, not your judgment.
1. Treat the arguments as the goal (or a `goal.md` checkbox file if one is named).
2. ORCHESTRATE FIRST — call the knitbrain_run tool with the goal and ADHERE to its verdict: adopt the returned SKILL (refine it, then knitbrain_skill_save); if it proposes agents, spawn them via your host's sub-agent mechanism and coordinate on knitbrain_team_post.
3. Pick the verify command by precedence: an explicit --verify > the goal file's `VERIFY:` line > `npm test` when a package.json exists. If none is derivable, ASK the user for the gate — do NOT invent a command that passes.
4. Read an optional --for <30m|1h> and convert it to deadline_ms.
5. Drive the knitbrain_run_loop tool each cycle with { goal, verify_cmd, max_iters, deadline_ms }: make the smallest real fix, then call knitbrain_run_loop again with the SAME goal so iteration + the time budget carry across calls.
6. NEVER fake met=true. Stop only at a real met=true, OR max_iters, OR the --for deadline, then report the honest final state (what passed, what is still open) and close the loop: knitbrain_record_learning + knitbrain_skill_outcome.

For a HANDS-OFF autonomous run (a FRESH agent per iteration, in the background), use /loop instead — it launches the external runner (knitbrain loop).
"""
9 changes: 9 additions & 0 deletions .gemini/commands/loop.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
description = "Launch the autonomous external runner (knitbrain loop) in the background"
prompt = """
Launch knitbrain's EXTERNAL runner in the BACKGROUND, then report the handle. Do NOT run the loop inline — it would block this session.
1. Resolve a goal file from the arguments: a markdown file with `- [ ] task` checkboxes (default `goal.md`). If it is missing, tell the user to run `knitbrain onboard` first and stop — do NOT invent tasks.
2. Using your terminal tool, run DETACHED (pass through any --for/--max/--verify/--reviewer the user gave):
nohup knitbrain loop <goalfile> --for 1h --agent "gemini -p" > <goalfile>.loop.log 2>&1 & echo "loop PID $!"
3. Report the PID + log path (`<goalfile>.loop.log`). The runner spawns a FRESH "gemini -p" per `- [ ]` task, runs the verify gate, and ticks `- [x]` only on green. Watch the boxes tick, tail the log, or run `knitbrain dashboard`. Stop early with `kill <PID>`.
4. Do NOT tick any box yourself — only the runner's verify (and optional reviewer) gate marks a task done. No false green.
"""
59 changes: 59 additions & 0 deletions .gemini/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"hooks": {
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "knitbrain-hook sessionstart"
}
]
}
],
"BeforeTool": [
{
"matcher": "Read",
"hooks": [
{
"type": "command",
"command": "knitbrain-hook pretooluse"
}
]
}
],
"AfterTool": [
{
"matcher": "Bash|Grep|Glob|WebFetch|WebSearch",
"hooks": [
{
"type": "command",
"command": "knitbrain-hook posttooluse"
}
]
}
],
"PreCompress": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "knitbrain-hook precompact"
}
]
}
],
"AfterAgent": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "knitbrain-hook stop"
}
]
}
]
}
}
13 changes: 13 additions & 0 deletions .github/prompts/goal.prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
description: Drive a goal to a verify gate WITH YOU in this session (in-chat orchestration)
---

Drive the goal in the arguments to done WITH YOU in THIS session (single context). The verify gate is the truth, not your judgment.
1. Treat the arguments as the goal (or a `goal.md` checkbox file if one is named).
2. ORCHESTRATE FIRST — call the knitbrain_run tool with the goal and ADHERE to its verdict: adopt the returned SKILL (refine it, then knitbrain_skill_save); if it proposes agents, spawn them via your host's sub-agent mechanism and coordinate on knitbrain_team_post.
3. Pick the verify command by precedence: an explicit --verify > the goal file's `VERIFY:` line > `npm test` when a package.json exists. If none is derivable, ASK the user for the gate — do NOT invent a command that passes.
4. Read an optional --for <30m|1h> and convert it to deadline_ms.
5. Drive the knitbrain_run_loop tool each cycle with { goal, verify_cmd, max_iters, deadline_ms }: make the smallest real fix, then call knitbrain_run_loop again with the SAME goal so iteration + the time budget carry across calls.
6. NEVER fake met=true. Stop only at a real met=true, OR max_iters, OR the --for deadline, then report the honest final state (what passed, what is still open) and close the loop: knitbrain_record_learning + knitbrain_skill_outcome.

For a HANDS-OFF autonomous run (a FRESH agent per iteration, in the background), use /loop instead — it launches the external runner (knitbrain loop).
10 changes: 10 additions & 0 deletions .github/prompts/loop.prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
description: Launch the autonomous external runner (knitbrain loop) in the background
---

Launch knitbrain's EXTERNAL runner in the BACKGROUND, then report the handle. Do NOT run the loop inline — it would block this session.
1. Resolve a goal file from the arguments: a markdown file with `- [ ] task` checkboxes (default `goal.md`). If it is missing, tell the user to run `knitbrain onboard` first and stop — do NOT invent tasks.
2. Using your terminal tool, run DETACHED (pass through any --for/--max/--verify/--reviewer the user gave):
nohup knitbrain loop <goalfile> --for 1h --agent "claude -p" > <goalfile>.loop.log 2>&1 & echo "loop PID $!"
3. Report the PID + log path (`<goalfile>.loop.log`). The runner spawns a FRESH "claude -p" per `- [ ]` task, runs the verify gate, and ticks `- [x]` only on green. Watch the boxes tick, tail the log, or run `knitbrain dashboard`. Stop early with `kill <PID>`.
4. Do NOT tick any box yourself — only the runner's verify (and optional reviewer) gate marks a task done. No false green.
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,10 @@ One engine, three ways in — the headless loop is the front door:
passes; questions get answered directly.
- **Two slash front doors, on every host that has a slash surface** (Claude Code, Codex, Gemini,
VS Code Copilot, Windsurf — Cursor via terminal):
- **`/goal <done-means>`** drives the gate **with you, in this session** — `knitbrain_run`
- **`/goal-knitbrain <done-means>`** drives the gate **with you, in this session** — `knitbrain_run`
orchestrates a skill + agents, then `knitbrain_run_loop` runs your verify command each cycle
until it exits 0. Single context, interactive.
- **`/loop goal.md --for 2h`** hands off to the **external runner** (`knitbrain loop`): it
- **`/loop-knitbrain goal.md --for 2h`** hands off to the **external runner** (`knitbrain loop`): it
*launches detached*, spawns a fresh agent per checkbox, and owns the loop itself — surviving
your context window, not depending on any model choosing to continue. A slash command can't
*be* an hour-long loop, so it launches the runner and hands back a watch handle.
Expand All @@ -132,7 +132,7 @@ alert on 1.

```cron
# weekdays 9am: drive the goal for up to 2h, lint as the independent reviewer
0 9 * * 1-5 cd /path/to/repo && knitbrain loop goal.md --for 2h --reviewer "npm run lint" >> ~/.knitbrain/loop.log 2>&1
0 9 * * 1-5 cd /path/to/repo && knitbrain loop goal.md --for 2h --reviewer "npm run lint" >> ~/.knitbrain/loop-knitbrain.log 2>&1
```

Same one-liner works as a launchd `ProgramArguments`, a CI cron job step, or the command behind
Expand Down Expand Up @@ -196,19 +196,19 @@ The optimizer is identical everywhere; what differs is reach:

| Platform | MCP tools | Hook enforcement | Auto-compression | Slash commands |
|---|---|---|---|---|
| Claude Code | ✅ | ✅ full (deny · stop-block · inject · rewrite) | ✅ hooks | `/goal` `/loop` `/meter` `/handoff` `/terse` (`.claude/commands`) |
| Codex CLI | ✅ | ✅ full (`.codex/hooks.json`) | hooks + `knitbrain_read` | `/goal` `/loop` (`~/.codex/prompts`) |
| Claude Code | ✅ | ✅ full (deny · stop-block · inject · rewrite) | ✅ hooks | `/goal-knitbrain` `/loop-knitbrain` `/meter` `/handoff` `/terse` (`.claude/commands`) |
| Codex CLI | ✅ | ✅ full (`.codex/hooks.json`) | hooks + `knitbrain_read` | `/goal-knitbrain` `/loop-knitbrain` (`~/.codex/prompts`) |
| Cursor | ✅ | ✅ deny + follow-up loop (`.cursor/hooks.json`) | hooks + `knitbrain_read` | — (no slash API; documented in rules) |
| Gemini CLI | ✅ | ✅ deny + AfterAgent loop (`.gemini/settings.json`) | hooks + `knitbrain_read` | `/goal` `/loop` (`.gemini/commands/*.toml`) |
| VS Code Copilot | ✅ | ✅ full (reads `.claude/settings.json` natively) | hooks + `knitbrain_read` | `/goal` `/loop` (`.github/prompts/*.prompt.md`) |
| Windsurf | ✅ | ✅ deny-only (exit-2) (`.windsurf/hooks.json`) | hooks + `knitbrain_read` | `/goal` `/loop` (`.windsurf/workflows`) |
| Gemini CLI | ✅ | ✅ deny + AfterAgent loop (`.gemini/settings.json`) | hooks + `knitbrain_read` | `/goal-knitbrain` `/loop-knitbrain` (`.gemini/commands/*.toml`) |
| VS Code Copilot | ✅ | ✅ full (reads `.claude/settings.json` natively) | hooks + `knitbrain_read` | `/goal-knitbrain` `/loop-knitbrain` (`.github/prompts/*.prompt.md`) |
| Windsurf | ✅ | ✅ deny-only (exit-2) (`.windsurf/hooks.json`) | hooks + `knitbrain_read` | `/goal-knitbrain` `/loop-knitbrain` (`.windsurf/workflows`) |
| Cline · any other MCP client | ✅ | — (advisory; hooks planned where APIs allow) | via `knitbrain_read` | — (runner works from any terminal) |
| Any agent, API key | ✅ | — | ✅ proxy (full wire) | — |

One hook binary serves every row: it detects the calling platform from the payload and answers in
that host's schema. Where a host's API can't do something (Cursor can't block stop; Gemini can't
rewrite output), knitbrain degrades to the nearest honest mechanism instead of claiming otherwise.
`/goal` and `/loop` ship for every host with a slash-command surface — each in that host's native
`/goal-knitbrain` and `/loop-knitbrain` ship for every host with a slash-command surface — each in that host's native
format — so both front doors are the same everywhere. Cursor has no such surface; there the runner
is a terminal command (`knitbrain loop`), documented in its always-on rules.

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "knitbrain",
"version": "0.20.0",
"version": "0.20.1",
"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",
Expand Down
4 changes: 2 additions & 2 deletions src/mcp/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1089,12 +1089,12 @@ export const TOOLS: readonly ToolDef[] = [
"",
...tasks,
"",
"Drive hands-off: `/loop goal.md --for 1h` (autonomous external runner) or `/goal` in this session. CLI: `knitbrain loop goal.md`.",
"Drive hands-off: `/loop-knitbrain goal.md --for 1h` (autonomous external runner) or `/goal-knitbrain` in this session. CLI: `knitbrain loop goal.md`.",
].join("\n"),
"utf8",
);
const checkboxCount = tasks.filter((t) => t.startsWith("- [ ]")).length;
goalNote = ` goal.md written (${checkboxCount} checkbox${checkboxCount === 1 ? "" : "es"}, VERIFY honored by the loop) — start with \`/loop goal.md --for 1h\` (autonomous runner) or \`/goal\` in-session.`;
goalNote = ` goal.md written (${checkboxCount} checkbox${checkboxCount === 1 ? "" : "es"}, VERIFY honored by the loop) — start with \`/loop-knitbrain goal.md --for 1h\` (autonomous runner) or \`/goal-knitbrain\` in-session.`;
}
return `Onboarding complete — Project Charter ("${r.page}") + constraints skill ("${r.skill}") + workflow written (ROUTING covers: ${domains.join(", ") || "none"}). knitbrain_load_session now surfaces your intent + workflow every session.${gapHint}${goalNote}`;
}
Expand Down
Loading
Loading