See pipeline-design.md for the full design rationale.
None. The pipeline is implemented entirely with existing Harvey packages and the Go standard library.
| File | Purpose |
|---|---|
harvey/pipeline.go |
All pipeline logic: arg parsing, file reading, @mention scan, model resolution, confidence extraction, step execution, orchestrator |
harvey/pipeline_test.go |
Unit and integration tests |
| File | Change |
|---|---|
harvey/commands.go |
Register /pipeline in the command dispatch table |
harvey/terminal.go |
Extend buildCompleter: add /pipeline with
path positions starting at token index 2 |
func parsePipelineArgs(root string, args []string) (threshold float64, files []string, err error)args[0] matches \d+(\.\d+)?%;
parse to float64 in (0, 1]resolveWorkspacePath (path
escape blocked)func readPipelineFile(root, relPath string) (body string, err error)
func scanAtMention(body string) string // returns "" if none foundreadPipelineFile resolves and reads; enforces workspace
boundaryscanAtMention applies regex @([\w:.-]+)
and returns the first capture groupfunc resolvePipelineClient(a *Agent, mention string) (LLMClient, error)a.Client, nil (no
allocation)AnyLLMClient using same
provider as a.Client but with model name = mentionfunc extractConfidence(ctx context.Context, client LLMClient, response string) (score float64, stripped string, method string, err error){"confidence": X.X ...} JSON at end of response;
strip block"Rate your confidence 0.0–1.0. Reply only: CONFIDENCE: <score>";
parse replyReturns the score, the response with the confidence block removed, the method used (“json”, “followup”, “keyword”), and any error from the follow-up call.
func runPipelineStep(
ctx context.Context,
a *Agent,
client LLMClient,
messages []Message,
out io.Writer,
stepNum, total int,
filename string,
threshold float64,
) (strippedResponse string, confidence float64, err error)User
message[N/total] filename | context X%client.Chat(ctx, messages, out) — streams to
terminalextractConfidence on resultfunc cmdPipeline(a *Agent, args []string, out io.Writer) errorparsePipelineArgs — validate threshold and filesreadPipelineFile →
scanAtMention → resolvePipelineClient
a.History + user message from
filerunPipelineStep for each step; stop on errora.AddMessage("assistant", finalStrippedResponse)CUT BACK TO: original sceneIn buildCompleter switch statement, add:
case "/pipeline":
pathStart = 2 // tokens[1] is confidence %, paths start at index 2pipeline_test.go)| Test | Covers |
|---|---|
TestParsePipelineArgs_valid |
90%, 85.5%, single and multiple files |
TestParsePipelineArgs_invalid |
Missing %, non-numeric, zero files, path escape |
TestScanAtMention_first |
First @mention wins, ignores later ones |
TestScanAtMention_none |
Returns empty string |
TestExtractConfidence_json |
Well-formed JSON block at end of response |
TestExtractConfidence_followup |
JSON absent, follow-up succeeds |
TestExtractConfidence_keyword |
Both JSON and follow-up fail, keyword scan used |
TestCmdPipeline_singleStep |
One file, confidence met, History updated |
TestCmdPipeline_multiStep |
Three files, all pass, final response appended |
TestCmdPipeline_failAtStep2 |
Confidence fails at step 2, History unchanged |
TestCmdPipeline_mentionUnresolved |
@mention not found, stops before step 1 |
TestCmdPipeline_fileNotFound |
Missing file, stops with error |