local-executor 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +301 -0
- package/dist/cli.js +2606 -0
- package/package.json +69 -0
- package/skill/adapters/claude-code/SKILL.md +45 -0
- package/skill/adapters/codex/AGENTS.block.md +13 -0
- package/skill/adapters/codex/SKILL.md +6 -0
- package/skill/adapters/cursor/local-executor.mdc +19 -0
- package/skill/adapters/windsurf/local-executor.md +18 -0
- package/skill/core/PIPELINE.md +109 -0
- package/skill/core/audit-prompt.md +51 -0
- package/skill/core/executor-system-prompt.md +34 -0
- package/skill/core/handoff-template.md +65 -0
- package/skill/core/modern-practices.md +61 -0
- package/skill/runtime/check_local.mjs +56 -0
- package/skill/runtime/config.json +10 -0
- package/skill/runtime/run_executor.mjs +225 -0
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "local-executor",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Set up a planner → local executor → auditor AI coding pipeline: installs Ollama, picks a right-sized open-weight model for your hardware, and installs the skill into Claude Code, Codex CLI, Cursor, and Windsurf.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"bin": {
|
|
8
|
+
"lex": "dist/cli.js",
|
|
9
|
+
"local-executor": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"skill",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=20"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup",
|
|
22
|
+
"dev": "tsup --watch",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"lint": "biome check .",
|
|
27
|
+
"lint:fix": "biome check --write .",
|
|
28
|
+
"prepublishOnly": "npm run build && npm test"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"ollama",
|
|
32
|
+
"local-llm",
|
|
33
|
+
"claude-code",
|
|
34
|
+
"codex",
|
|
35
|
+
"cursor",
|
|
36
|
+
"windsurf",
|
|
37
|
+
"ai-coding",
|
|
38
|
+
"agent",
|
|
39
|
+
"qwen",
|
|
40
|
+
"gemma",
|
|
41
|
+
"cli"
|
|
42
|
+
],
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/Raghdkun/local-executor.git"
|
|
46
|
+
},
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/Raghdkun/local-executor/issues"
|
|
49
|
+
},
|
|
50
|
+
"homepage": "https://github.com/Raghdkun/local-executor#readme",
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@clack/prompts": "^1.7.0",
|
|
53
|
+
"commander": "^15.0.0",
|
|
54
|
+
"execa": "^9.6.1",
|
|
55
|
+
"picocolors": "^1.1.1",
|
|
56
|
+
"systeminformation": "^5.33.8"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@biomejs/biome": "^2.5.12",
|
|
60
|
+
"@types/node": "^22.20.1",
|
|
61
|
+
"tsup": "^8.5.1",
|
|
62
|
+
"typescript": "^7.0.2",
|
|
63
|
+
"vitest": "^5.0.0"
|
|
64
|
+
},
|
|
65
|
+
"publishConfig": {
|
|
66
|
+
"access": "public"
|
|
67
|
+
},
|
|
68
|
+
"author": "local-executor contributors"
|
|
69
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: local-executor-pipeline
|
|
3
|
+
description: Three-role coding pipeline where Claude plans and writes tests, a local open-weight model via Ollama writes the code, and an Opus subagent audits the result. Use this whenever the user says "use the local model", "use the local executor", "hand this to the executor", "run the pipeline", "delegate the coding", mentions Ollama/Qwen/Gemma for a coding task, or wants to save cloud tokens by offloading implementation work to a local LLM.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Local Executor Pipeline (Claude Code adapter)
|
|
7
|
+
|
|
8
|
+
Read `{{LEX_CORE}}/PIPELINE.md` now and follow it. This file only covers what is specific to Claude Code.
|
|
9
|
+
|
|
10
|
+
Installed by `local-executor` v{{LEX_VERSION}}. Executor model: `{{LEX_MODEL}}` (from `{{LEX_CONFIG}}`).
|
|
11
|
+
|
|
12
|
+
## Running the scripts
|
|
13
|
+
|
|
14
|
+
Use the Bash tool:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
node "{{LEX_RUNTIME}}/check_local.mjs"
|
|
18
|
+
node "{{LEX_RUNTIME}}/run_executor.mjs" --packet .lex/packet-1.md --out .lex/response-1.md
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Write packets under `.lex/` in the repo (add it to `.gitignore` if it is not already) so the user can inspect them.
|
|
22
|
+
|
|
23
|
+
## Inventory step (Step 1 in PIPELINE.md)
|
|
24
|
+
|
|
25
|
+
- Skills: list `~/.claude/skills/` and `./.claude/skills/`; the ones already loaded in your context count too.
|
|
26
|
+
- MCP tools: whatever `mcp__*` tools you see in your tool list. Prefer a docs MCP (e.g. context7) over guessing an API when writing the packet.
|
|
27
|
+
|
|
28
|
+
## Audit step (Step 4 in PIPELINE.md)
|
|
29
|
+
|
|
30
|
+
Spawn the auditor with the Task tool. It must be a **separate subagent** so its context contains only the audit prompt, the packet, the diff, and the test output:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
Task(
|
|
34
|
+
subagent_type: "general-purpose",
|
|
35
|
+
model: "opus",
|
|
36
|
+
description: "Audit local-executor diff",
|
|
37
|
+
prompt: <contents of {{LEX_CORE}}/audit-prompt.md with PACKET, DIFF, TEST_OUTPUT filled in>
|
|
38
|
+
)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Never audit in your own context when the Task tool is available. The auditor may read the repo but must not edit it; say so in the prompt.
|
|
42
|
+
|
|
43
|
+
## Escalation
|
|
44
|
+
|
|
45
|
+
When PIPELINE.md says to escalate, do the task yourself in this same session and tell the user in one line why the executor could not finish.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
## Local executor pipeline (installed by local-executor v{{LEX_VERSION}})
|
|
2
|
+
|
|
3
|
+
When the user says "use the local model", "use the local executor", "hand this to the executor", "run the pipeline", or wants to save cloud tokens on implementation work, follow `{{LEX_CORE}}/PIPELINE.md`. You are the **planner**: you write the plan and the tests; the local model (`{{LEX_MODEL}}`, configured in `{{LEX_CONFIG}}`) writes the code; a separate reviewer pass audits it.
|
|
4
|
+
|
|
5
|
+
Codex-specific notes:
|
|
6
|
+
|
|
7
|
+
- Check the executor: `node "{{LEX_RUNTIME}}/check_local.mjs"`.
|
|
8
|
+
- Run a packet: `node "{{LEX_RUNTIME}}/run_executor.mjs" --packet .lex/packet-1.md --out .lex/response-1.md`. The script only talks to `127.0.0.1:11434`. If the sandbox blocks that call, ask for approval to run it outside the sandbox rather than disabling the sandbox globally.
|
|
9
|
+
- Inventory (Step 1): skills live in `~/.codex/skills/` and in sections of this file; MCP servers are in `~/.codex/config.toml`.
|
|
10
|
+
- Audit (Step 4): run a **second** Codex invocation with a fresh context so the reviewer has not seen your planning:
|
|
11
|
+
`codex exec --model <strongest model you have> "$(cat .lex/audit-1.md)"`
|
|
12
|
+
where `.lex/audit-1.md` is `{{LEX_CORE}}/audit-prompt.md` with PACKET, DIFF, and TEST_OUTPUT filled in. Paste its `VERDICT` back into your reasoning and act on it. If you cannot run a second invocation, do the audit in a separate pass and say that self-review is weaker.
|
|
13
|
+
- Escalate per Step 5 and say why in one line.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: local-executor-pipeline
|
|
3
|
+
description: Plan and write tests here, let a local Ollama model ({{LEX_MODEL}}) write the code, then audit with a fresh reviewer pass. Use when the user says "use the local model", "use the local executor", "run the pipeline", or wants to save cloud tokens on implementation work.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Read `{{LEX_CORE}}/PIPELINE.md` and the "Local executor pipeline" section of `~/.codex/AGENTS.md`, then follow them. Scripts: `{{LEX_RUNTIME}}/check_local.mjs`, `{{LEX_RUNTIME}}/run_executor.mjs`. Config: `{{LEX_CONFIG}}`.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Local executor pipeline — plan and write tests in Cursor, let a local Ollama model ({{LEX_MODEL}}) write the code, audit in a fresh chat. Apply when the user says "use the local model", "use the local executor", "run the pipeline", or wants to save cloud tokens on implementation work.
|
|
3
|
+
globs:
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Local executor pipeline (Cursor adapter, installed by local-executor v{{LEX_VERSION}})
|
|
8
|
+
|
|
9
|
+
Read `{{LEX_CORE}}/PIPELINE.md` and follow it. You are the **planner**. The local model writes code; you never let it plan or decide scope.
|
|
10
|
+
|
|
11
|
+
Cursor-specific notes:
|
|
12
|
+
|
|
13
|
+
- Run scripts in the integrated terminal:
|
|
14
|
+
`node "{{LEX_RUNTIME}}/check_local.mjs"`
|
|
15
|
+
`node "{{LEX_RUNTIME}}/run_executor.mjs" --packet .lex/packet-1.md --out .lex/response-1.md`
|
|
16
|
+
- Inventory (Step 1): other rules in `.cursor/rules/` and any MCP servers configured in Cursor settings. Use a docs MCP to get exact API facts into the packet.
|
|
17
|
+
- Audit (Step 4): Cursor cannot spawn a subagent. Tell the user: "Opening a fresh chat for the audit so the reviewer has not seen my planning." Then open a **new chat** with the strongest available model, paste `{{LEX_CORE}}/audit-prompt.md` with PACKET, DIFF, and TEST_OUTPUT filled in, and bring the `VERDICT` back here. Do not audit in this chat unless the user declines; if so, say self-review is weaker.
|
|
18
|
+
- Escalate per Step 5 and say why in one line.
|
|
19
|
+
- Config: `{{LEX_CONFIG}}`. Change the model with `lex switch <tag>`, not by editing rules.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
trigger: model_decision
|
|
3
|
+
description: Local executor pipeline — plan and write tests in Windsurf, let a local Ollama model ({{LEX_MODEL}}) write the code, audit in a fresh conversation. Apply when the user says "use the local model", "use the local executor", "run the pipeline", or wants to save cloud tokens on implementation work.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Local executor pipeline (Windsurf adapter, installed by local-executor v{{LEX_VERSION}})
|
|
7
|
+
|
|
8
|
+
Read `{{LEX_CORE}}/PIPELINE.md` and follow it. You are the **planner**. The local model writes code; you never let it plan or decide scope.
|
|
9
|
+
|
|
10
|
+
Windsurf-specific notes:
|
|
11
|
+
|
|
12
|
+
- Run scripts in the terminal:
|
|
13
|
+
`node "{{LEX_RUNTIME}}/check_local.mjs"`
|
|
14
|
+
`node "{{LEX_RUNTIME}}/run_executor.mjs" --packet .lex/packet-1.md --out .lex/response-1.md`
|
|
15
|
+
- Inventory (Step 1): other rules in `.windsurf/rules/`, workflows in `.windsurf/workflows/`, and MCP servers configured in Windsurf. Use a docs MCP to get exact API facts into the packet.
|
|
16
|
+
- Audit (Step 4): Cascade cannot spawn a subagent. Tell the user: "Starting a new conversation for the audit so the reviewer has not seen my planning." Then open a **new Cascade conversation** with the strongest available model, paste `{{LEX_CORE}}/audit-prompt.md` with PACKET, DIFF, and TEST_OUTPUT filled in, and bring the `VERDICT` back here. Do not audit in this conversation unless the user declines; if so, say self-review is weaker.
|
|
17
|
+
- Escalate per Step 5 and say why in one line.
|
|
18
|
+
- Config: `{{LEX_CONFIG}}`. Change the model with `lex switch <tag>`, not by editing rules.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Local Executor Pipeline
|
|
2
|
+
|
|
3
|
+
You are the **planner**. A small local model running in Ollama is the **executor**. A strong model in a separate context is the **auditor**. Each role does one thing, and the handoffs between them are strict, because a small model is only reliable when its task is narrow and its output is checked by something stronger.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
user request
|
|
7
|
+
│
|
|
8
|
+
▼
|
|
9
|
+
┌─────────┐ task packet ┌──────────────┐ diff + test log ┌─────────┐
|
|
10
|
+
│ PLANNER │ ───────────────▶ │ EXECUTOR │ ──────────────────▶ │ AUDITOR │
|
|
11
|
+
│ (you) │ │ (local LLM) │ │ (strong)│
|
|
12
|
+
└─────────┘ ◀─────────────── └──────────────┘ ◀───────────────── └─────────┘
|
|
13
|
+
▲ retry with verdict: ACCEPT / REJECT + reasons
|
|
14
|
+
└──────────────────── apply or loop (max 3) ──────────────────┘
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The local model is a cost saver, not a replacement. When it can't do the job within the limits below, you do the job.
|
|
18
|
+
|
|
19
|
+
This file is agent-neutral. The adapter that loaded it (Claude Code skill, Codex AGENTS block, Cursor/Windsurf rule) tells you how to spawn the auditor in your environment. Files for this install live at:
|
|
20
|
+
|
|
21
|
+
- Core docs: `{{LEX_CORE}}`
|
|
22
|
+
- Runtime scripts and config: `{{LEX_RUNTIME}}`
|
|
23
|
+
- Configured executor model: `{{LEX_MODEL}}` (read `{{LEX_CONFIG}}`; never hard-code a tag)
|
|
24
|
+
|
|
25
|
+
## Step 0 — Make sure the executor exists
|
|
26
|
+
|
|
27
|
+
Run:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
node "{{LEX_RUNTIME}}/check_local.mjs"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
It prints `READY`, `NOT RUNNING`, or `MISSING MODEL`, with the fix. If anything is missing, tell the user to run `npx local-executor` (or `lex doctor`). Do not pull models yourself without asking; downloads are several GB.
|
|
34
|
+
|
|
35
|
+
## Step 1 — Inventory what you have (30 seconds, once per task)
|
|
36
|
+
|
|
37
|
+
Before planning, list in one or two lines:
|
|
38
|
+
|
|
39
|
+
- **Skills available on this machine** relevant to the task. Claude Code: `~/.claude/skills` and `./.claude/skills`. Codex: sections in `AGENTS.md` and `~/.codex/skills`. Cursor: `.cursor/rules`. Windsurf: `.windsurf/rules`. A test-runner skill, a repo-conventions skill, a docs skill — use them to write a better packet.
|
|
40
|
+
- **MCP tools connected** to this agent that help: documentation lookup, issue tracker, database schema, browser. Use them during planning to get the facts the executor will need pasted into the packet.
|
|
41
|
+
|
|
42
|
+
State which ones you will use for this task, e.g. "Using: context7 MCP for the Prisma API; repo's `testing` skill for the test command." If none apply, say "No extra skills/tools needed."
|
|
43
|
+
|
|
44
|
+
The executor gets **no tools and no skills**. Everything it needs must be in the packet. Your inventory step is how you find that information; it is not something you hand off.
|
|
45
|
+
|
|
46
|
+
## Step 2 — Plan (you)
|
|
47
|
+
|
|
48
|
+
Turn the user's request into one or more **task packets**. A packet is the entire world the executor will see, so it has to be self-contained. Read `{{LEX_CORE}}/handoff-template.md` and follow it exactly.
|
|
49
|
+
|
|
50
|
+
Rules that matter for a small model:
|
|
51
|
+
|
|
52
|
+
- One packet = one file, or one function, or one tightly scoped change. If a request touches four files, that is four packets, run in dependency order.
|
|
53
|
+
- **Write the tests first, yourself, before the executor sees anything.** Put them in the repo. The packet tells the executor which test command must pass. This is the single biggest lever on quality: the executor can't argue with a failing test.
|
|
54
|
+
- Paste the relevant existing code into the packet verbatim. Do not describe it; the executor can't open files.
|
|
55
|
+
- State conventions explicitly, and **always include the modern-practices block** for the target language from `{{LEX_CORE}}/modern-practices.md`: current stable language version, idiomatic patterns, no deprecated APIs, typed where the language supports it, explicit error handling, no `any` / `interface{}`-style escape hatches unless the packet justifies them.
|
|
56
|
+
- Say what NOT to do (don't refactor, don't add dependencies, don't touch other files).
|
|
57
|
+
|
|
58
|
+
## Step 3 — Execute (local model)
|
|
59
|
+
|
|
60
|
+
Write the packet to a file (for example `.lex/packet-1.md` inside the repo, or a temp dir), then run:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
node "{{LEX_RUNTIME}}/run_executor.mjs" --packet <packet.md> --out <response.md> [--apply --root <repo>]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The script sends the packet to Ollama with the system prompt in `{{LEX_CORE}}/executor-system-prompt.md`, which forces the executor to return only fenced code blocks tagged with file paths. It writes the raw response to `--out` and, with `--apply`, also writes each block to its file path under `--root` (creating a `.bak` backup alongside). Exit codes: `0` ok, `2` Ollama error, `3` no code blocks, `4` the executor declared it cannot do the task.
|
|
67
|
+
|
|
68
|
+
Default flow: run without `--apply`, read the output, then apply and run the test command from the packet yourself. If tests fail, decide whether the failure is a planning error (fix the packet) or an execution error (retry, appending the failure output under `## Previous attempt failed`). Cap at **3 attempts per packet**.
|
|
69
|
+
|
|
70
|
+
## Step 4 — Audit (strong model, separate context)
|
|
71
|
+
|
|
72
|
+
Only once the tests pass. The auditor is **never the local model** and **never the same context that wrote the packet**. Use `{{LEX_CORE}}/audit-prompt.md`, filling in the packet, the diff, and the test output.
|
|
73
|
+
|
|
74
|
+
- **Claude Code**: spawn a subagent with `model: opus` via the Task tool, with the audit prompt as its task.
|
|
75
|
+
- **Codex CLI**: run a second `codex exec` invocation with the audit prompt as the task (a fresh context, ideally a stronger model via `--model`).
|
|
76
|
+
- **Cursor / Windsurf**: they cannot spawn subagents. Open a fresh chat/composer, paste the audit prompt, and bring the verdict back. Tell the user you are doing this and why.
|
|
77
|
+
- If none of the above is possible, do the audit yourself in a separate pass and say so; self-review is weaker.
|
|
78
|
+
|
|
79
|
+
The auditor returns `ACCEPT` or `REJECT` with a numbered, severity-tagged list of issues. On `REJECT`, feed the issues back as a new executor attempt (counts toward the 3-attempt cap). On `ACCEPT`, apply the change (if not already applied) and move to the next packet.
|
|
80
|
+
|
|
81
|
+
## Step 5 — Escalate when the pipeline can't finish
|
|
82
|
+
|
|
83
|
+
You take over the task yourself, and log one line saying why, when any of these happen:
|
|
84
|
+
|
|
85
|
+
- 3 attempts on a packet without passing tests and audit.
|
|
86
|
+
- The packet would exceed ~6,000 tokens of pasted code even after splitting.
|
|
87
|
+
- The executor returns prose instead of code twice in a row, or exits with code `4` (declared it cannot).
|
|
88
|
+
- The task needs tools (network, DB, browser) during implementation, not just during planning.
|
|
89
|
+
|
|
90
|
+
Example log line: `Escalating: 3 attempts on packet-2 (auth middleware); executor kept dropping the async error path. Doing it myself.`
|
|
91
|
+
|
|
92
|
+
## Step 6 — Report
|
|
93
|
+
|
|
94
|
+
When all packets are done, tell the user in a few sentences: what was changed, how many executor attempts it took, what the auditor flagged, and anything you had to do by hand. Don't paste the full diff unless asked.
|
|
95
|
+
|
|
96
|
+
## When to skip the pipeline
|
|
97
|
+
|
|
98
|
+
If the task is a one-line fix, a rename, or something you can do faster than writing a packet, just do it and mention that the pipeline wasn't worth invoking. The pipeline earns its overhead on medium tasks: implementing a spec'd function, filling in a module against tests, mechanical but non-trivial code.
|
|
99
|
+
|
|
100
|
+
## Files in this install
|
|
101
|
+
|
|
102
|
+
- `{{LEX_CONFIG}}` — model name, Ollama URL, context size, timeouts
|
|
103
|
+
- `{{LEX_RUNTIME}}/check_local.mjs` — is everything installed and running?
|
|
104
|
+
- `{{LEX_RUNTIME}}/run_executor.mjs` — send a packet, get code back, optionally apply
|
|
105
|
+
- `{{LEX_CORE}}/handoff-template.md` — exact packet format for the executor
|
|
106
|
+
- `{{LEX_CORE}}/executor-system-prompt.md` — the system prompt the executor runs under
|
|
107
|
+
- `{{LEX_CORE}}/modern-practices.md` — per-language conventions block to paste into packets
|
|
108
|
+
- `{{LEX_CORE}}/audit-prompt.md` — exact prompt for the auditor and its verdict format
|
|
109
|
+
- `{{LEX_CORE}}/models.md` — which local model fits which hardware (generated for this machine)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Auditor prompt
|
|
2
|
+
|
|
3
|
+
The auditor is a **strong model in a fresh context**: never the local executor, never the planner's own context. How you get a fresh context depends on your agent:
|
|
4
|
+
|
|
5
|
+
- **Claude Code**: Task tool, `model: opus`, `subagent_type: general-purpose`, this prompt as the task.
|
|
6
|
+
- **Codex CLI**: `codex exec --model <strongest available> "<this prompt>"` from the repo root (a second invocation, not the current one).
|
|
7
|
+
- **Cursor / Windsurf**: open a new chat/composer and paste this prompt. Bring the verdict back to the planning chat.
|
|
8
|
+
|
|
9
|
+
The auditor should have read access to the repo so it can look at neighboring code, but it must not edit anything. Fill in the three placeholders and send as the task.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
You are auditing a code change written by a small local language model. The change already passes its tests. Your job is to catch what tests don't: correctness gaps, security issues, and code that will hurt later.
|
|
13
|
+
|
|
14
|
+
## The task packet the executor received
|
|
15
|
+
{PACKET}
|
|
16
|
+
|
|
17
|
+
## The diff it produced
|
|
18
|
+
{DIFF}
|
|
19
|
+
|
|
20
|
+
## Test output
|
|
21
|
+
{TEST_OUTPUT}
|
|
22
|
+
|
|
23
|
+
Review the diff against the packet. Check, in this order:
|
|
24
|
+
1. Correctness — does it actually satisfy the Goal, or just the tests? Look for edge cases the tests don't cover (empty input, None/null, unicode, concurrency, off-by-one).
|
|
25
|
+
2. Scope — did it touch anything outside "Files you may change"? Did it violate any "Do NOT"?
|
|
26
|
+
3. Safety — injection, unsafe deserialization, path traversal, secrets in code, unbounded resource use.
|
|
27
|
+
4. Fit — does it match the stated conventions, including the modern-practices block, and the surrounding codebase? Any deprecated API, untyped escape hatch, or swallowed error is at least a major.
|
|
28
|
+
5. Tests — are the packet's tests themselves adequate? If a critical case is missing, say which one.
|
|
29
|
+
|
|
30
|
+
Respond with exactly this format:
|
|
31
|
+
|
|
32
|
+
VERDICT: ACCEPT | REJECT
|
|
33
|
+
|
|
34
|
+
ISSUES:
|
|
35
|
+
1. [severity: blocker|major|minor] <file:line if applicable> — <one or two sentences, concrete, actionable>
|
|
36
|
+
2. ...
|
|
37
|
+
|
|
38
|
+
(If ACCEPT with no issues, write "ISSUES: none".)
|
|
39
|
+
|
|
40
|
+
MISSING TESTS:
|
|
41
|
+
- <test case description, or "none">
|
|
42
|
+
|
|
43
|
+
Reject for any blocker. Accept with listed minors is fine. Do not rewrite the code yourself; describe the fix precisely enough that a small model can apply it.
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## How the planner uses the verdict
|
|
47
|
+
|
|
48
|
+
- `ACCEPT` → apply and move on. Add any "MISSING TESTS" to the repo if they're cheap.
|
|
49
|
+
- `REJECT` → build a retry packet: copy the original, append the ISSUES list under `## Previous attempt failed`, and re-run the executor. Counts toward the 3-attempt cap.
|
|
50
|
+
- If the auditor flags a **planning** problem (bad packet, inadequate tests), fix the packet yourself rather than retrying blindly.
|
|
51
|
+
- Never skip the audit because "the tests pass". Passing tests is the entry ticket to the audit, not a substitute for it.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
You are a code executor. You receive a task packet and return code. Do exactly what the packet says. Nothing more.
|
|
2
|
+
|
|
3
|
+
OUTPUT FORMAT (this matters most)
|
|
4
|
+
- Reply with fenced code blocks only. No words before, between, or after them. No headings. No explanations.
|
|
5
|
+
- Each block's info string is exactly: <language> path=<relative/file/path>
|
|
6
|
+
- Each block holds the COMPLETE new contents of that file. Never a fragment. Never a diff.
|
|
7
|
+
- One block per file you change. Only files listed under "Files you may change".
|
|
8
|
+
|
|
9
|
+
RULES
|
|
10
|
+
- Make the tests under "Tests that must pass" pass. Never edit the tests.
|
|
11
|
+
- Follow "Conventions" exactly, including the modern-practices bullets. Use the stated language version. No deprecated APIs. No untyped escape hatches.
|
|
12
|
+
- Do not refactor, rename, reorder, or reformat code the packet did not ask you to change.
|
|
13
|
+
- Do not add dependencies unless the packet allows them.
|
|
14
|
+
- If the packet has "Previous attempt failed", fix that specific failure and nothing else.
|
|
15
|
+
- If the packet is impossible or contradictory, reply with exactly one block:
|
|
16
|
+
```text path=EXECUTOR_CANNOT.md
|
|
17
|
+
<one to three lines saying what is missing or contradictory>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
EXAMPLE OF A CORRECT REPLY (two files changed):
|
|
21
|
+
|
|
22
|
+
```python path=src/utils.py
|
|
23
|
+
def add(a: int, b: int) -> int:
|
|
24
|
+
"""Return the sum of a and b."""
|
|
25
|
+
return a + b
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```python path=src/__init__.py
|
|
29
|
+
from .utils import add
|
|
30
|
+
|
|
31
|
+
__all__ = ["add"]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
That is the entire reply. Start your reply with three backticks.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Task packet format
|
|
2
|
+
|
|
3
|
+
The executor sees nothing but this document. Every packet uses this exact structure. Sections marked (required) must never be empty.
|
|
4
|
+
|
|
5
|
+
```markdown
|
|
6
|
+
# Task: <one-line title>
|
|
7
|
+
|
|
8
|
+
## Goal (required)
|
|
9
|
+
<2–4 sentences. What the code must do when finished. State the observable behavior, not the implementation.>
|
|
10
|
+
|
|
11
|
+
## Files you may change (required)
|
|
12
|
+
- path/to/file.py — <what changes here>
|
|
13
|
+
|
|
14
|
+
You may NOT change any other file.
|
|
15
|
+
|
|
16
|
+
## Conventions (required)
|
|
17
|
+
- Language/version: <e.g. Python 3.12>
|
|
18
|
+
- Style: <e.g. type hints on all functions, no print(), use logging>
|
|
19
|
+
- Allowed dependencies: <e.g. stdlib only>
|
|
20
|
+
- Naming: <anything the repo cares about>
|
|
21
|
+
- Modern practices (required — copy the block for this language from modern-practices.md):
|
|
22
|
+
- <bullet 1>
|
|
23
|
+
- <bullet 2>
|
|
24
|
+
- ...
|
|
25
|
+
|
|
26
|
+
## Existing code (required if the file exists)
|
|
27
|
+
### path/to/file.py
|
|
28
|
+
```python
|
|
29
|
+
<full current contents, verbatim>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Tests that must pass (required)
|
|
33
|
+
Command: `<exact command, e.g. pytest tests/test_utils.py -q>`
|
|
34
|
+
|
|
35
|
+
### tests/test_utils.py
|
|
36
|
+
```python
|
|
37
|
+
<full contents of the test file the planner wrote, verbatim>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Do NOT
|
|
41
|
+
- <refactor unrelated code>
|
|
42
|
+
- <add new dependencies>
|
|
43
|
+
- <change function signatures listed above>
|
|
44
|
+
|
|
45
|
+
## Previous attempt failed (only on retry)
|
|
46
|
+
Attempt <n> produced this test output:
|
|
47
|
+
```
|
|
48
|
+
<pasted failure output, trimmed to the relevant part>
|
|
49
|
+
```
|
|
50
|
+
Fix this specific failure.
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Why each section exists
|
|
54
|
+
|
|
55
|
+
- **Goal** first, because small models anchor on whatever comes first.
|
|
56
|
+
- **Files you may change** bounds the blast radius. Without it, executors "helpfully" rewrite neighbors.
|
|
57
|
+
- **Existing code verbatim**: the executor cannot read the disk. If you summarize instead of pasting, it will hallucinate the parts you skipped.
|
|
58
|
+
- **Tests verbatim**: this is the contract. The executor optimizes for making the tests pass, which is exactly what you want when you wrote the tests.
|
|
59
|
+
- **Conventions → Modern practices** is mandatory. Small models default to whatever was most common in their training data, which is often years out of date. The block pins the language version, the idioms, and the escape hatches that are off limits.
|
|
60
|
+
- **Do NOT** is more effective than positive instructions for small models. Be concrete.
|
|
61
|
+
- **Previous attempt failed** turns a retry into a targeted fix rather than a fresh guess.
|
|
62
|
+
|
|
63
|
+
## Sizing
|
|
64
|
+
|
|
65
|
+
If the packet exceeds ~6,000 tokens of pasted code, it is too big for one executor call. Split it: either by file, or by extracting the specific function and its immediate dependencies.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Modern-practices blocks
|
|
2
|
+
|
|
3
|
+
Paste the block for the target language into the packet's **Conventions → Modern practices** list. Adjust versions to what the repo actually uses (check `package.json`, `pyproject.toml`, `go.mod`, `Cargo.toml`, `*.csproj`, `Package.swift`). If the repo is older than the versions below, say so in the packet and pin to the repo's version; do not let the executor "upgrade" the project. Last reviewed: 2026-09-06.
|
|
4
|
+
|
|
5
|
+
Every block is short on purpose: a small model follows five concrete bullets better than a page of guidance. Add one or two repo-specific bullets (formatter, import order, logging library) and stop.
|
|
6
|
+
|
|
7
|
+
## TypeScript / JavaScript
|
|
8
|
+
- TypeScript ≥ 5.9 (7.x if the repo uses it), `strict: true`. ESM (`import`/`export`), not CommonJS, unless the repo is CJS.
|
|
9
|
+
- No `any`. Use `unknown` + narrowing, or precise types. No non-null assertions (`!`) without a comment.
|
|
10
|
+
- `async`/`await`; never unhandled promises. Errors are thrown or returned as typed results, not swallowed.
|
|
11
|
+
- Prefer `const`; no `var`. Optional chaining and nullish coalescing over manual checks.
|
|
12
|
+
- Node ≥ 20 APIs: `fetch`, `node:fs/promises`, `node:path`, `structuredClone`. No `request`, no callbacks-style fs.
|
|
13
|
+
- Tests: vitest or the repo's runner. Named exports. No default exports for libraries.
|
|
14
|
+
|
|
15
|
+
## Python
|
|
16
|
+
- Python ≥ 3.12 (3.11 minimum). Type hints on every function signature; `list[str]` / `X | None`, not `List`/`Optional`. `from __future__ import annotations` if the repo targets 3.9/3.10.
|
|
17
|
+
- Dataclasses or Pydantic for structured data, not dicts passed around.
|
|
18
|
+
- `pathlib.Path`, not `os.path`. f-strings, not `%` or `.format()`.
|
|
19
|
+
- Explicit exceptions; never bare `except:`. Context managers for resources.
|
|
20
|
+
- No mutable default arguments. No wildcard imports.
|
|
21
|
+
- Tests: pytest, plain `assert`.
|
|
22
|
+
|
|
23
|
+
## Go
|
|
24
|
+
- Go ≥ 1.24 (1.22 minimum, for range-over-int and loop-var semantics). Errors are returned and wrapped with `fmt.Errorf("...: %w", err)`; never ignored with `_` unless justified in a comment.
|
|
25
|
+
- `context.Context` as first parameter for anything that does I/O.
|
|
26
|
+
- Generics where they remove duplication; interfaces small and defined at the consumer.
|
|
27
|
+
- `slices`, `maps`, `log/slog` from the standard library. No `ioutil`.
|
|
28
|
+
- Table-driven tests with `t.Run`.
|
|
29
|
+
|
|
30
|
+
## Rust
|
|
31
|
+
- Edition 2024 (2021 minimum). `Result<T, E>` with `?`; no `unwrap()`/`expect()` outside tests and `main`.
|
|
32
|
+
- `thiserror` for library errors, `anyhow` only at binary boundaries (if the repo allows the dependency).
|
|
33
|
+
- Borrow, don't clone, unless clarity demands it and a comment says so. No `unsafe` unless the packet allows it.
|
|
34
|
+
- Clippy-clean at default level.
|
|
35
|
+
|
|
36
|
+
## Java / Kotlin
|
|
37
|
+
- Java ≥ 21 (records, sealed types, pattern matching for switch, virtual threads; 17 minimum). Kotlin ≥ 2.1 (K2 compiler, data classes, sealed interfaces, coroutines for async).
|
|
38
|
+
- Immutability by default: `final` fields / `val`. `Optional` / nullable types instead of null checks scattered everywhere.
|
|
39
|
+
- No raw types. No checked-exception swallowing.
|
|
40
|
+
- JUnit 5 / Kotest.
|
|
41
|
+
|
|
42
|
+
## Swift
|
|
43
|
+
- Swift ≥ 6 with strict concurrency where the package enables it (5.9 minimum). `struct` by default, `class` only when reference semantics are needed. Value types `Sendable` where shared.
|
|
44
|
+
- `async`/`await` and structured concurrency; no completion-handler APIs in new code.
|
|
45
|
+
- `guard` for early exits; no force-unwraps (`!`) outside tests.
|
|
46
|
+
- Swift Testing or XCTest per the repo.
|
|
47
|
+
|
|
48
|
+
## C#
|
|
49
|
+
- .NET ≥ 9 (8 LTS minimum), nullable reference types enabled, file-scoped namespaces, records for DTOs.
|
|
50
|
+
- `async`/`await` end to end with `CancellationToken` parameters. No `.Result` / `.Wait()`.
|
|
51
|
+
- Pattern matching and switch expressions. `IReadOnlyList<T>` on public surfaces.
|
|
52
|
+
- xUnit.
|
|
53
|
+
|
|
54
|
+
## Shell (when unavoidable)
|
|
55
|
+
- Bash: `set -euo pipefail`, quote every variable, `[[ ]]` tests, no parsing `ls`.
|
|
56
|
+
- PowerShell: `Set-StrictMode -Version Latest`, `$ErrorActionPreference = 'Stop'`.
|
|
57
|
+
|
|
58
|
+
## Universal
|
|
59
|
+
- Match the repo's existing formatter/linter config; do not introduce a new style.
|
|
60
|
+
- Every public function has a one-line doc comment stating what it does and what it returns.
|
|
61
|
+
- No commented-out code, no `TODO` in delivered code, no debug prints.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Reports whether Ollama is running and has the configured model.
|
|
4
|
+
* Works on macOS, Linux, Windows. Exit 0 = ready; 1 = something missing.
|
|
5
|
+
*
|
|
6
|
+
* Usage: node check_local.mjs [--json]
|
|
7
|
+
*/
|
|
8
|
+
import { readFile } from "node:fs/promises";
|
|
9
|
+
import { dirname, join } from "node:path";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
|
+
|
|
12
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const configPath = join(here, "config.json");
|
|
14
|
+
const json = process.argv.includes("--json");
|
|
15
|
+
|
|
16
|
+
function report(status, message, extra = {}) {
|
|
17
|
+
if (json) console.log(JSON.stringify({ status, message, config: configPath, ...extra }));
|
|
18
|
+
else console.log(`${status}: ${message}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let config;
|
|
22
|
+
try {
|
|
23
|
+
config = JSON.parse(await readFile(configPath, "utf8"));
|
|
24
|
+
} catch (err) {
|
|
25
|
+
report("BROKEN CONFIG", `cannot read ${configPath}: ${err.message}. Re-run: npx local-executor`);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let tags;
|
|
30
|
+
try {
|
|
31
|
+
const res = await fetch(`${config.ollama_url}/api/tags`, { signal: AbortSignal.timeout(3000) });
|
|
32
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
33
|
+
tags = await res.json();
|
|
34
|
+
} catch {
|
|
35
|
+
report(
|
|
36
|
+
"NOT RUNNING",
|
|
37
|
+
`ollama server not reachable at ${config.ollama_url}. Start it (open the Ollama app, or run: ollama serve) or install it: npx local-executor`,
|
|
38
|
+
{ model: config.model },
|
|
39
|
+
);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const names = (tags.models ?? []).map((m) => m.name);
|
|
44
|
+
const have = names.includes(config.model) || names.includes(`${config.model}:latest`);
|
|
45
|
+
if (!have) {
|
|
46
|
+
report("MISSING MODEL", `${config.model} not pulled. Run: ollama pull ${config.model}`, {
|
|
47
|
+
model: config.model,
|
|
48
|
+
available: names,
|
|
49
|
+
});
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
report("READY", `ollama running at ${config.ollama_url} with model ${config.model}`, {
|
|
54
|
+
model: config.model,
|
|
55
|
+
available: names,
|
|
56
|
+
});
|