Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ orca run implement.sc "add a rate limiter to /login"
```

Useful flags: `--skip-branch` (continue on the current branch instead of
creating one) and `--keep-changes` (leave uncommitted files in place instead of
stashing them).
creating one), `--keep-changes` (leave uncommitted files in place instead of
stashing them) and `--worktree` (run in a git worktree of this repository
instead of the current checkout).

In every mode, which agent (and model) handles the planning, coding, and review
roles comes from `settings.properties` — written for you by the shell's
Expand Down Expand Up @@ -337,6 +338,20 @@ Each `flow(...)` run is bound to exactly one feature branch and one progress log
stashes. A run that already has a progress log — a resume, or one too broken
to read — always stashes and ignores `--keep-changes`, so an interrupted
stage's partial work can't leak into the stage that re-runs.
`--worktree` (`OrcaArgs.worktree`) runs the whole flow in
`.orca/worktrees/<hash>` of this repository — a second checkout, keyed on the
same prompt hash as the progress log, created on the first run and reused by
every later one for that task. It isolates the run: two tasks can run at once
without sharing a checkout or a branch. Uncommitted work does NOT come along —
a worktree is made from a commit — so `--worktree` is refused with
`--skip-branch` and with `--keep-changes`. The first run in a worktree pays a
cold build (no build outputs, no dependencies, none of the untracked local
config a project may need), an editor or indexer that ignores `.gitignore`
will see the second checkout, and orca never removes it. The run starts on an
`orca-worktree-<hash>` branch orca also never deletes, so full cleanup is `git
worktree remove .orca/worktrees/<hash>` **and** `git branch -d
orca-worktree-<hash>`; a re-run of the task refuses rather than moving that
branch if it has gained commits since.
Sharp edge: kept files are unprotected until that first stage commit — a
failure before it runs the teardown's `git reset --hard` and destroys kept
modifications to tracked files (kept untracked files survive).
Expand Down Expand Up @@ -951,7 +966,7 @@ action non-interactively and exits.

| Command | Key flags | Does |
|---|---|---|
| `orca run <flow> [task]` | `--verbose` (stack trace on abort), `--skip-branch`, `--keep-changes` (leave uncommitted files in place), `--honor-pin` (use the flow's own pinned orca version) | run a flow, propagating its exit code; task is read from stdin when omitted and piped |
| `orca run <flow> [task]` | `--verbose` (stack trace on abort), `--skip-branch`, `--keep-changes` (leave uncommitted files in place), `--worktree` (run in a git worktree of this repository), `--honor-pin` (use the flow's own pinned orca version) | run a flow, propagating its exit code; task is read from stdin when omitted and piped |
| `orca view <flow>` | `--plain`, `--color` | print a flow's source (highlighted when stdout is a terminal) |
| `orca edit <flow>` | `--to project\|global` | open a flow in `$VISUAL`/`$EDITOR`/vi (`--to` required to customize a built-in) |
| `orca create "<goal>"` | `--name <file>`, `--global` | author a new flow: the built-in `simple.sc` flow writes it in an isolated sandbox with the configured role agents; `--name` is auto-derived when omitted |
Expand Down
16 changes: 16 additions & 0 deletions adr/0018-stage-bound-flow-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,22 @@ the wrong branch.
> `git reset --hard` and destroys kept modifications to tracked files. Kept
> untracked files survive: R5's clean is skipped for this run too, for the
> reason its own text gives.

> **Amendment (2026-08-27).** `OrcaArgs.worktree` (`--worktree`) runs the flow
> in `.orca/worktrees/<prompt hash>` of this repository instead of the current
> checkout. The FIRST run in a freshly created worktree always meets this
> requirement's clean case: a worktree is created from a commit, so its tree
> is clean by construction. A REUSED worktree — every resume, and every re-run
> of the same task text — is subject to the same dirty-tree policy as any
> other directory: a user's edits, or a SIGKILLed run's partial ones, are
> still there, and the prompt fires normally. Uncommitted work in the invoking
> checkout stays there. The run starts on an `orca-worktree-<hash>` branch
> that orca creates and never deletes; it refuses to move that branch if it
> has since gained commits. `--worktree` is therefore refused with `--keep-changes` (the
> files it names are in the other checkout and do not come along) and with
> `--skip-branch` (git will not check the current branch out a second time in
> a new worktree). Both refusals happen in `OrcaArgs.parse`, before setup, the
> banner, or any git call.
- **R5** — On **successful** exit the progress-log file is removed in a final
commit, and a feature branch left with no changes other than the progress log is
deleted (throwaway-branch cleanup). That removal commit is also pushed, but only
Expand Down
13 changes: 13 additions & 0 deletions adr/0019-project-stack-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ flips to the safe direction:
CACHEDIR.TAG # backup/sync tools skip the dir
flow.lock
lint-*.txt # spilled lint output
worktrees/
.gitignore # written by orca, contains "*" (self-ignoring)
<hash>/ # a --worktree run's own checkout
```

- Ephemeral state moves under `.orca/cache/`, which orca creates with a
Expand All @@ -126,6 +129,16 @@ flips to the safe direction:
`Lint`, and `ProgressStore` each create `.orca` independently, and `Lint`
resolves it against `os.pwd` where the others use `workDir` — reconciled
while moving).

> **Amendment (2026-08-27).** `worktrees/` is the exception to this rule: it
> is ignored but not ephemeral, and deliberately sits OUTSIDE `cache/`. A
> `--worktree` run's checkout holds unmerged work, and after a failure the
> only copy of the progress log that resumes it — neither belongs under a
> `CACHEDIR.TAG` announcing the directory as safe to delete, which is why
> `worktrees/` gets the self-ignoring `.gitignore` and no tag. `OrcaDir` is
> the one helper that writes that marker, as for `cache/` above, and it
> writes it before the first worktree is created: without it, `git add -A` in
> the checkout stages the worktree as an embedded git repository.
- The progress-log `forceAdd` **stays**. It is load-bearing, not a hack: in a
repo that still gitignores `.orca/`, a plain stage `git add -A` would skip
the log, and failure teardown's `reset --hard` would then leave an on-disk
Expand Down
54 changes: 54 additions & 0 deletions adr/0021-orca-shell.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,35 @@ runtime's own glyph family (`⏺`/`●`/`▶`/`▸`).
> fallback. Multiple unfinished logs (different prompts, one branch) offer
> only the newest by mtime.

> **Amendment (2026-08-27).** The scan spans the checkout the shell was started
> in plus the worktrees orca made FOR THAT CHECKOUT — the ones under its own
> `.orca/worktrees/`, matching where the data lives, since `.orca/` is
> per-checkout. So the checkout that made the worktrees sees itself and all of
> them, while a worktree, whose own `.orca/worktrees/` is empty, sees only
> itself; surveying every run means running the shell from the checkout the
> worktrees hang off. A `--worktree` run leaves
> its progress log inside its own tree, so a shell scanning only its own
> directory would either offer nothing or offer an older run. The
> newest-by-mtime rule now orders across all of them, and a directory that
> cannot be read costs only its own logs. Discovery is git's own worktree list
> (`Worktrees.list`, resolved at the call site so the scan itself takes plain
> directories and stays testable without a repository), filtered to children of
> `.orca/worktrees/` and capped at the 20 most recently used (orca never removes
> a worktree, and these scans run per redraw) — a worktree checked out to review
> someone else's branch
> carries that branch's committed progress log, and its recorded task text is
> what the offer would hand an agent. The progress-log scan deliberately does
> NOT descend into `.orca/worktrees/`; it stays one level deep.
>
> The offer carries the directory its log was found in, names it in the menu
> label when it is not the shell's own, and the resume RUNS there. No
> shell-voice notice on top: the child recognises an orca worktree from its own
> working directory rather than from the flag, so its closing summary already
> names the tree and offers a `git -C` diff for it. Not `--worktree`: that flag re-derives a path from the task text, which
> is the directory holding the log only when the log was already in an orca
> worktree of that exact prompt — otherwise it would silently start a fresh run
> in a tree with no log, leaving the interrupted one behind.

> **Amendment (2026-08-01).** A `branch: <name>` line prints directly above
> the menu prompt, re-read on every redraw (like Continue's manifest listing
> and the resume check) so it stays true after a flow run switches branches —
Expand Down Expand Up @@ -477,6 +506,21 @@ resume is global, but the resumed context still references that directory):
| gemini | `gemini --list-sessions` → match uuid → `gemini --resume <index>` | medium — `--resume` takes latest/index, not uuid |
| pi | `pi --session-dir <workDir>/.orca/cache/pi-sessions/<id> --continue` | medium-high — orca writes the dir itself; inferred from pi's `--continue` semantics, not yet live-verified interactively |

> **Amendment (2026-08-27).** The listing spans the checkout the shell was
> started in plus the worktrees orca made for it (`WorktreeScan.dirs`, the same
> set the resume offer scans, §3): a `--worktree` run writes its manifests into
> its own tree, so a shell reading only its own `.orca/cache/runs/` would omit
> the sessions of a run it had just started. The newest-first order now runs
> across all of them. Containment is per directory as well as per file: the
> caller's own directory is read strictly (a symlinked `.orca` there aborts),
> while a failure in any other — unreadable, or removed mid-redraw — becomes one
> warning naming it rather than taking the listing down with it. Lineages are
> keyed on the manifest's `workDir` too, since flow session names are static and
> harness sessions are cwd-scoped: the same name in two worktrees is two
> conversations, and the rows say which tree each is in. Reattaching needs
> nothing further — resume already execs from the manifest's recorded
> `workDir`, which is the worktree.

> **Amendment (2026-07-28).** Pi is now durable (ADR 0018 §2.6); before the argv is
> built, resume applies the same resumability predicate as the backend's own probe
> (`PiSessionStore.resumable`: a `*.jsonl` whose transcript header matches the
Expand Down Expand Up @@ -851,6 +895,16 @@ the same thing (`--global`, `--json`, `--yes`). `create`/`fork` run the
built-in authoring flow (§9) with the configured role agents — no
harness/model/yolo flag exists for either.

> **Amendment (2026-08-27).** `run` gains `--worktree`, passed straight
> through to the flow child like `--verbose`/`--skip-branch`/`--keep-changes`.
> `RunCli` also refuses the two contradictory pairs (`--worktree` with
> `--skip-branch`, and with `--keep-changes`) itself, exiting 2 before any
> `scala-cli` spawn — the child refuses them too and stays the authority, but
> the shell holds the answer already, and spawning only to be told costs a
> dependency resolution. Both sides call the one shared decision
> (`OrcaArgs.worktreeRefusal`), so neither the wording nor the set of refused
> pairs can drift.

Both entry points call a shared `orca.shell.actions` package (`FlowResolution`,
`RunAction`, `ViewAction`, `EditAction`, `AuthorAction`, `SessionAction`,
`ConfigAction`, `StackAction`): each takes fully-resolved parameters and does
Expand Down
Loading
Loading