promptpilot
v0.2.2
Published
A code-first prompt optimizer, session memory layer, and downstream model router for Claude CLI and agentic LLM workflows.
Maintainers
Readme
promptpilot
A local prompt optimizer and model router for Claude CLI and agentic LLM workflows.
Before your prompt reaches a remote model, PromptPilot rewrites it locally using a small Ollama model — cutting noise, compressing context, and routing to the right downstream model. No prompt rewrite costs you remote tokens.
Install
npm install -g promptpilotRequires Ollama running locally and Node.js >= 20.10.0.
Pull at least one small local model:
ollama pull qwen2.5:3bWhat it does
- Rewrites your prompt locally before sending it anywhere
- Keeps session memory across turns so context carries forward
- Compresses old context when it gets too long
- Routes to the best model from a list you provide
- Outputs plain text for shell pipelines or JSON for tooling
Quick start
# Optimize a prompt and print the result
promptpilot optimize "explain binary search simply" --plain
# Pipe directly into Claude
promptpilot optimize "continue my study guide" --session dsa --save-context --plain | claude
# Read from a file
cat notes.txt | promptpilot optimize --task summarization --plain | claudeSession memory
Pass --session <name> to persist context across calls. PromptPilot stores sessions as JSON under ~/.promptpilot/sessions by default.
# Save context after each turn
promptpilot optimize "start a refactor plan" --session repo-refactor --save-context --plain
# Pick up where you left off
promptpilot optimize "continue the refactor" --session repo-refactor --save-context --plain | claude
# Clear a session when you're done
promptpilot optimize --session repo-refactor --clear-sessionCustom compressor model
PromptPilot ships a Modelfile that builds promptpilot-compressor — a stripped-down Ollama model tuned to output only the rewritten prompt with no extra commentary.
ollama pull qwen2.5:3b
ollama create promptpilot-compressor -f ./ModelfileUse it:
promptpilot optimize "help me refactor this auth middleware" \
--model promptpilot-compressor \
--preset code \
--plainDownstream model routing
Tell PromptPilot which models you're allowed to use and it picks the best one for the job.
promptpilot optimize "rewrite this for a coding refactor" \
--task code \
--preset code \
--target anthropic:claude-sonnet \
--target openai:gpt-4.1-mini \
--target openai:gpt-5-codex \
--target-hint coding \
--target-hint refactor \
--json --debugLibrary usage
Basic optimization
import { createOptimizer } from "promptpilot";
const optimizer = createOptimizer({
provider: "ollama",
host: "http://localhost:11434",
contextStore: "local"
});
const result = await optimizer.optimize({
prompt: "help me debug this failing CI job",
task: "code",
preset: "code",
sessionId: "ci-fix",
saveContext: true
});
console.log(result.finalPrompt);
console.log(result.model);Routing across multiple models
const result = await optimizer.optimize({
prompt: "rewrite this prompt for a coding refactor task",
task: "code",
preset: "code",
availableTargets: [
{
provider: "anthropic",
model: "claude-sonnet",
label: "anthropic:claude-sonnet",
capabilities: ["coding", "writing"],
costRank: 2
},
{
provider: "openai",
model: "gpt-4.1-mini",
label: "openai:gpt-4.1-mini",
capabilities: ["writing", "chat"],
costRank: 1
},
{
provider: "openai",
model: "gpt-5-codex",
label: "openai:gpt-5-codex",
capabilities: ["coding", "agentic", "tool_use", "debugging"],
costRank: 3
}
],
routingPriority: "cheapest_adequate",
targetHints: ["coding", "agentic", "refactor"],
workloadBias: "code_first",
debug: true
});
console.log(result.selectedTarget);
console.log(result.rankedTargets);
console.log(result.routingReason);Non-coding tasks work too
const result = await optimizer.optimize({
prompt: "write a short internship follow-up email",
task: "email",
preset: "email",
availableTargets: [
{
provider: "anthropic",
model: "claude-sonnet",
label: "anthropic:claude-sonnet",
capabilities: ["coding", "writing"],
costRank: 2
},
{
provider: "openai",
model: "gpt-4.1-mini",
label: "openai:gpt-4.1-mini",
capabilities: ["writing", "email", "chat"],
costRank: 1
}
]
});
console.log(result.selectedTarget);Node child_process pipeline
import { spawn } from "node:child_process";
const promptpilot = spawn("promptpilot", [
"optimize",
"continue working on this repo refactor",
"--session", "repo-refactor",
"--save-context",
"--plain"
]);
const claude = spawn("claude", [], { stdio: ["pipe", "inherit", "inherit"] });
promptpilot.stdout.pipe(claude.stdin);CLI flags
| Flag | What it does |
|---|---|
| --session <id> | Name the session for persistent memory |
| --save-context | Write this turn back into the session |
| --clear-session | Wipe a session and start fresh |
| --no-context | Ignore session history for this call |
| --model <name> | Use a specific local Ollama model |
| --preset <preset> | Prompt style: code, email, essay, support, summarization, chat |
| --mode <mode> | Rewrite mode: clarity, concise, detailed, structured, persuasive, compress, claude_cli |
| --task <task> | Task hint passed to the optimizer |
| --tone <tone> | Tone hint passed to the optimizer |
| --target <provider:model> | Add a downstream model to the routing pool (repeatable) |
| --target-hint <value> | Capability hint for routing (repeatable) |
| --routing-priority <value> | cheapest_adequate, best_quality, or fastest_adequate |
| --routing-top-k <n> | How many ranked targets to return |
| --workload-bias <value> | code_first to bias routing toward coding models |
| --no-routing | Skip downstream routing entirely |
| --plain | Output the final prompt as plain text |
| --json | Output full result as JSON |
| --debug | Include routing and optimization details in output |
| --host <url> | Ollama host (default: http://localhost:11434) |
| --store <local\|sqlite> | Session storage backend |
| --storage-dir <path> | Custom path for session files |
| --sqlite-path <path> | Path to SQLite database file |
| --max-total-tokens <n> | Token budget for the full composed prompt |
| --max-context-tokens <n> | Token budget for retrieved session context |
| --max-input-tokens <n> | Token budget for the incoming prompt |
| --timeout <ms> | Ollama request timeout in milliseconds |
| --bypass-optimization | Skip Ollama and pass the prompt through as-is |
| --pin-constraint <text> | Add a pinned constraint (repeatable) |
| --tag <value> | Tag this session entry (repeatable) |
| --output-format <text> | Output format hint |
| --max-length <n> | Max length hint for the rewritten prompt |
| --target-model <name> | Alternate flag for downstream model name |
If no prompt text is given, promptpilot optimize reads from stdin.
How local model selection works
PromptPilot prefers small Ollama models (≤ 4B params). If only one suitable model is installed, it uses it directly. If multiple are installed, a local Qwen router picks the best one for the task. Explicit --model always overrides this.
Default preference order:
qwen2.5:3bphi3:minillama3.2:3b
If Ollama is unavailable or times out, PromptPilot falls back to deterministic prompt shaping (whitespace cleanup, mode-specific wrappers) instead of failing outright.
Exports
import {
createOptimizer,
optimizePrompt,
PromptOptimizer,
OllamaClient,
FileSessionStore,
SQLiteSessionStore
} from "promptpilot";Key fields on the result object:
| Field | Description |
|---|---|
| optimizedPrompt | The rewritten prompt from the local model |
| finalPrompt | The composed prompt including context |
| selectedTarget | The downstream model chosen by the router |
| rankedTargets | All targets ranked by the router |
| routingReason | Why the top target was selected |
| routingWarnings | Any issues the router flagged |
| provider | Which provider ran the optimization (ollama or heuristic) |
| model | Which local model was used |
| estimatedTokensBefore | Token estimate before optimization |
| estimatedTokensAfter | Token estimate after optimization |
License
MIT
