docs · 13
The model is outside the orchestration.
The phases are fixed. The tools per phase are fixed. The model fills in the reasoning inside a boundary held in Rust.
ksforge implement --change "As a user, I want to reset my password via email."
tap a phase to see its tool grant
the problem
One continuous turn blurs the edge between reading and writing.
ksforge used to run implement/fix as a single Claude Code turn that explored, edited, and reported in one breath. That design had a real, observed failure mode.
Earlier, a write-capable capability's tool grant covered the entire turn from its first token — editing and exploring shared the same permission window. Each phase now gets its own grant, scoped before ACT begins.
— paraphrased from docs/03-architecture.md
Read and write tools available from the first token. Whether the model explores before it edits depends on prompt discipline alone.
Five separate subprocess calls. Read-only tools until ACT — a Rust-level grant per phase, applied before each subprocess starts.
how it's fixed
The sequence is a Rust type, checked at compile time.
Each phase is its own subprocess invocation of claude. The model sees one phase's prompt at a time — it answers, the process exits, and ksforge decides what runs next.
— paraphrased from docs/03-architecture.md, “The phase loop”
domain::workflow::WorkflowState::Actrequires an existingLocatevalue to construct. The type system defines the one path from UNDERSTAND to ACT — through LOCATE.
answered by the host
Three questions the host answers directly.
Each one has a documented, host-only answer, fixed before the run starts.
“Is your change valid?”
Validation commands come from your own --validate flags, supplied by a human or workflow author, and run after the model reports completed — before ksforge trusts the result.
“What did you change?”
ksforge content-hashes every file under the workspace before and after ACT and diffs the two maps — the filesystem is ground truth; changed_files stays advisory.
“Are you done?”
REPORT is plain Rust, assembling the final result directly from what UNDERSTAND, LOCATE, ACT and VALIDATE already produced.
a run, traced
What one implement call actually does.
Five subprocess calls, one working directory, each phase's tool grant fixed before it starts.
Illustrative trace assembled from the documented subprocess contract in docs/03-architecture.md — the flags and phase order are real; this specific session output is a representative example.
where this differs
Two answers to “who runs the workflow.”
Some agent tools declare a contract and hand sequencing to “the model plus your harness” at runtime. ksforge fixes the sequence in Rust, compiled into the binary, and lets the model fill in only what each phase asks for.
Model is the runtime
- A
.contract.mddeclares intent; a harness compiles it once into a topology. - At run time, the model plus the harness works out the steps.
- Flexible across workflow shapes discovered at run time.
- Enforcement of “which tool, which phase” lives inside that runtime itself.
Host is the runtime
- Phase order, tool grant per phase, and “done” are Rust — compiled into the binary.
- A change request steers what ACT does, inside the phase order, tool grant, and VALIDATE step ksforge already fixed.
- Resuming a paused run re-enters a known
WorkflowStatevariant directly. - Optimized for a small, fixed capability set run unattended in CI, where a predictable phase order is the point.
why this trade
A deliberate trade for a specific job.
It's a different point in the same design space, optimized for flexibility across workflow shapes discovered at run time. ksforge optimizes for the opposite: implement / review / fix / explain, run unattended in CI, where a predictable phase order is the point.
Fixing the loop in Rust is also what makes waiting_for_human pause-and-resume reliable across a process boundary — resuming re-enters a known state directly, using the WorkflowState variant recorded when the run paused.