@@ -268,124 +268,82 @@ Any agent pattern can also opt into process isolation:
268268outcome = Speculate(candidates, isolate_processes = True , timeout = 60 )(ws)
269269```
270270
271- ## How it works
271+ ## CLI
272272
273- BranchContext uses copy-on-write filesystems to create instant, zero-cost
274- branches of your workspace. Two backends are supported, auto-detected at
275- runtime:
273+ The ` branching ` command exposes the agent patterns as shell commands.
274+ Auto-detects the workspace from your current directory, or pass ` -w PATH ` .
275+ All commands support ` --json ` for machine-readable output.
276276
277- | Backend | How branches work |
278- | ---| ---|
279- | ** [ BranchFS] ( https://github.com/multikernel/branchfs ) ** (FUSE) | Single mount; branches are virtual paths within it. First-winner-commit semantics. |
280- | ** [ DaxFS] ( https://github.com/multikernel/daxfs ) ** (kernel) | Separate mount per branch. Fastest option for DAX-capable storage. |
277+ ### run
281278
282- You just create a ` Workspace ` pointed at a mounted path - the backend is
283- detected automatically.
279+ Run a command in a new branch. Commits on exit 0, aborts on non-zero.
284280
285- Process isolation (` BranchContext ` ) uses unprivileged Linux user namespaces
286- to give each child its own filesystem view. No root required - works on any
287- Linux distribution with ` unprivileged_userns_clone=1 ` (the default).
281+ ``` bash
282+ branching run -- ./build.sh
283+ branching run --on-error none -- python train.py
284+ branching run --ask -- make test # prompt before commit/abort
285+ ```
288286
289- ## API reference
287+ ### speculate
290288
291- The library has three layers. Imports are lazy - only the layer you use
292- gets loaded.
289+ Race N commands in parallel branches. First success wins.
293290
294- ``` python
295- from branching import Workspace # FS layer only
296- from branching import BranchContext # process layer only
297- from branching import Speculate # agent layer (+ FS layer)
291+ ``` bash
292+ branching speculate -c " ./fix_a.sh" -c " ./fix_b.sh" -c " ./fix_c.sh"
293+ branching speculate --timeout 60 -c " python solve_v1.py" -c " python solve_v2.py"
298294```
299295
300- ### Workspace and Branch
296+ ### best-of-n
301297
302- ** ` Workspace(path) ` ** - open a workspace from an existing mount .
298+ Run CMD N times in parallel, commit the highest-scoring success .
303299
304- | Property / Method | Description |
305- | ---| ---|
306- | ` .path ` | Mount root path |
307- | ` .fstype ` | Detected backend (` "branchfs" ` or ` "daxfs" ` ) |
308- | ` .branch(name, on_success="commit", on_error="abort") ` | Create a branch (returns ` Branch ` context manager) |
309-
310- ** ` Branch ` ** - context manager for an isolated workspace view.
300+ The child process can write a score to fd 3 (` echo 0.95 >&3 ` ).
301+ If nothing is written, score defaults to 1.0 for success / 0.0 for failure.
302+ Each child receives ` BRANCHING_ATTEMPT ` (0-indexed) in its environment.
311303
312- | Property / Method | Description |
313- | ---| ---|
314- | ` .name ` | Branch name |
315- | ` .path ` | Working directory for this branch |
316- | ` .branch_path ` | Full path (e.g. ` "/main/feature" ` ) |
317- | ` .branch(name, ...) ` | Create a nested child branch |
318- | ` .commit() ` | Merge changes into parent |
319- | ` .abort() ` | Roll back to parent |
304+ ``` bash
305+ branching best-of-n -n 5 -- ./solve.py
306+ branching best-of-n -n 3 --timeout 120 --json -- python attempt.py
307+ branching best-of-n -n 3 -- bash -c ' python run.py && echo "$SCORE" >&3'
308+ ```
320309
321- ` on_success ` accepts ` "commit" ` or ` None ` .
322- ` on_error ` accepts ` "abort" ` or ` None ` .
310+ ### reflexion
323311
324- ### BranchContext (process isolation)
312+ Sequential retry with optional critique feedback loop.
325313
326- ** ` BranchContext(target, workspace, *, close_fds=False) ` ** - run a function
327- in a sandboxed child process .
314+ The child receives ` BRANCHING_ATTEMPT ` (0-indexed) and ` BRANCHING_FEEDBACK `
315+ (empty on first attempt, critique output on retries) in its environment .
328316
329- | Property / Method | Description |
330- | ---| ---|
331- | ` target ` | ` Callable[[Path], None] ` - return normally for success, raise for failure |
332- | ` workspace ` | Directory to bind-mount into the child |
333- | ` .pid ` | Child PID |
334- | ` .alive ` | Whether the child is still running |
335- | ` .wait(timeout=None) ` | Block until exit; raises ` ProcessBranchError ` on failure, ` TimeoutError ` on timeout |
336- | ` .abort(timeout=5.0) ` | Abort child and all its descendants |
337-
338- ** ` BranchContext.create(targets, workspaces, *, close_fds=False) ` ** - fork N
339- children at once; cleans up all on exit.
317+ ``` bash
318+ branching reflexion --retries 5 -- ./fix.sh
319+ branching reflexion --retries 3 --critique " ./review.sh" -- ./solve.py
320+ branching reflexion --retries 3 --critique " python critique.py" --json -- python agent.py
321+ ```
340322
341- ### Agent patterns
323+ ### status
342324
343- All patterns: instantiate with config, call with a ` Workspace ` , get a
344- ` SpeculationOutcome ` .
325+ Show workspace info and active branches.
345326
346- | Pattern | Constructor | What it does |
347- | ---| ---| ---|
348- | ** ` Speculate ` ** | ` (candidates, *, first_wins=True, max_parallel=None, isolate_processes=False, timeout=None) ` | Run candidates in parallel; first success wins |
349- | ** ` BestOfN ` ** | ` (task, n=3, *, timeout=None) ` | Run N copies; commit highest-scoring success |
350- | ** ` Reflexion ` ** | ` (task, max_retries=3, *, critique=None) ` | Retry with critique feedback loop |
351- | ** ` TreeOfThoughts ` ** | ` (strategies, *, evaluate=None, expand=None, max_depth=1, timeout=None) ` | Parallel strategy tree with optional depth expansion |
352- | ** ` BeamSearch ` ** | ` (strategies, *, expand, evaluate=None, beam_width=3, max_depth=2, timeout=None) ` | Multi-level beam search; top-K branches survive each depth |
353- | ** ` Tournament ` ** | ` (task, n=4, *, judge, timeout=None) ` | Generate N candidates; pairwise elimination picks winner |
327+ ``` bash
328+ branching status
329+ branching status --json
330+ ```
354331
355- ### Result types
332+ ## How it works
356333
357- ** ` SpeculationOutcome ` ** - returned by all agent patterns.
334+ BranchContext uses copy-on-write filesystems to create instant, zero-cost
335+ branches of your workspace. Two backends are supported, auto-detected at
336+ runtime:
358337
359- | Field | Description |
338+ | Backend | How branches work |
360339| ---| ---|
361- | ` .committed ` | Whether a winner was committed |
362- | ` .winner ` | ` SpeculationResult ` or ` None ` |
363- | ` .all_results ` | All candidate results |
364-
365- ** ` SpeculationResult ` ** - one candidate's outcome.
340+ | ** [ BranchFS] ( https://github.com/multikernel/branchfs ) ** (FUSE) | Single mount; branches are virtual paths within it. First-winner-commit semantics. |
341+ | ** [ DaxFS] ( https://github.com/multikernel/daxfs ) ** (kernel) | Separate mount per branch. Fastest option for DAX-capable storage. |
366342
367- | Field | Description |
368- | ---| ---|
369- | ` .branch_index ` | Candidate index |
370- | ` .success ` | Whether the candidate succeeded |
371- | ` .score ` | Quality score (default 0.0) |
372- | ` .return_value ` | Raw return value |
373- | ` .exception ` | Exception if failed, else ` None ` |
374- | ` .branch_path ` | Working directory used |
343+ You just create a ` Workspace ` pointed at a mounted path - the backend is
344+ detected automatically.
375345
376- ### Exceptions
346+ Process isolation (` BranchContext ` ) uses unprivileged Linux user namespaces
347+ to give each child its own filesystem view. No root required - works on any
348+ Linux distribution with ` unprivileged_userns_clone=1 ` (the default).
377349
378- ```
379- BranchingError # base for all errors
380- ├── MountError # filesystem mount/unmount failed
381- ├── BranchError # branch operation failed
382- │ ├── BranchStaleError # a sibling branch was already committed
383- │ ├── BranchNotFoundError # branch does not exist
384- │ ├── CommitError # commit failed
385- │ │ └── ConflictError # another branch already committed
386- │ └── AbortError # abort failed
387- ├── ProcessBranchError # sandboxed child process failed
388- │ ├── ForkError # fork() failed
389- │ └── NamespaceError # sandbox setup failed
390- └── MemoryBranchError # memory branching failed
391- ```
0 commit comments