Skip to content

feat(lane): start an agent on a file prompt without a shell - #2532

Merged
mlorentedev merged 9 commits into
mainfrom
feat/lane-next
Oct 15, 2026
Merged

mlorentedev merged 9 commits into
mainfrom
feat/lane-next

Conversation

@mlorentedev

@mlorentedev mlorentedev commented Oct 15, 2026 •

Copy link
Copy Markdown
Owner

CLI-119 (#2528): hand a finished lane to the next queued issue, in one deterministic command for any project, OS and agent.

Summary

  • dotf lane next [--agent] [--dry-run] takes the first open, unassigned issue of the repo's queue (.dotf/lane.json), creates its worktree off the base through the repository's parent checkout in herdr, writes the rendered prompt and types <this dotf> lane exec --agent <a> --prompt-file <f> into the new pane. The agent defaults to the one in the calling pane. It never removes a worktree, and a second run for an item a workspace already shows starts nothing. With no backend it prints the commands.
  • dotf lane exec --agent <claude|pi|agy> --prompt-file <f> replaces the process with the agent's interactive command and passes the prompt as one argument: no shell, no quoting, same call from zsh, bash and PowerShell. On Windows dotf stays as the parent.
  • Backends sit behind lane.Backend (herdr first). The interface has no remove method, by design.
  • pi is launched through dotf secrets run --only NAN_API_KEY,OPENROUTER_API_KEY: its keys come from a shell function that exec skips. The key list is now copied in four launchers: The pi and opencode key lists are copied into four launchers #2534.
  • The successor runs the absolute path of the binary that decided, not dotf on the pane's PATH, which resolved to the pinned release and answered unknown command "lane" in the first real run.

One PR instead of the two the spec planned: about 600 executable lines for one mechanism whose second half is useless without the first.

Evidence (details in specs/CLI-119-lane-next/verification.md)

Landing note

.dotf/lane-prompt.md tells the successor to run dotf lane next on landing. Until the release carrying lane is the DOTF_VERSION pin and dotf update ran, that command is unknown command "lane" (the same coupling as #2517). Run it from a build of this branch until then.

SDD

Spec CLI-119-lane-next added; WIP-limit exception recorded with --over-wip-limit (owner, 2026-10-14). The spec stays active until an independent review signs it.

Knowledge

  • Lesson: docs/lessons/lesson-438-a-command-typed-into-a-pane-runs-the-panes-world-not-the-callers.md
  • ADR: none: a new command inside ADR-020's CLI layer, no new invariant
  • Runbook: none: the command's own help and the spec's verification cover it

dotf lane exec replaces the process with claude, pi or agy and hands it the
prompt as one argument, so quoting never applies and the same call works from
zsh, bash and PowerShell. pi is launched through dotf secrets run because its
keys come from a shell function that exec skips. Adds the queue and launch
packages the next step of the lane handoff builds on.
dotf lane next takes the first open, unassigned issue of the repo's queue,
creates its worktree through the repository's parent checkout in herdr and
types a plain lane exec command into the new pane, so the successor is the
same kind of agent running the same dotf. It never removes a worktree, and a
second run for an item a workspace already shows starts nothing. With no
backend it prints the commands.

Measured with claude and pi end to end; agy stops at its trust dialog (#2533).
@mlorentedev
mlorentedev marked this pull request as ready for review October 15, 2026 04:49
@coderabbitai

coderabbitai Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 30 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: mlorentedev/dotfiles/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c7af65d3-b326-4104-b369-f36392efbabc
📥 Commits

Reviewing files that changed from the base of the PR and between cfffe79 and 1496f1e.

📒 Files selected for processing: 25
  • .dotf/lane-prompt.md
  • .dotf/lane.json
  • .github/workflows/ci.yml
  • cli/internal/cmd/lane.go
  • cli/internal/cmd/lane_test.go
  • cli/internal/cmd/root.go
  • cli/internal/lane/exec_unix.go
  • cli/internal/lane/exec_windows.go
  • cli/internal/lane/gh.go
  • cli/internal/lane/gh_test.go
  • cli/internal/lane/handoff.go
  • cli/internal/lane/handoff_test.go
  • cli/internal/lane/herdr.go
  • cli/internal/lane/herdr_test.go
  • cli/internal/lane/launch.go
  • cli/internal/lane/launch_test.go
  • cli/internal/lane/queue.go
  • cli/internal/lane/queue_test.go
  • cli/internal/lane/runner.go
  • docs/lessons/_index.md
  • docs/lessons/lesson-438-a-command-typed-into-a-pane-runs-the-panes-world-not-the-callers.md
  • specs/CLI-119-lane-next/features.json
  • specs/CLI-119-lane-next/proposal.md
  • specs/CLI-119-lane-next/tasks.md
  • specs/CLI-119-lane-next/verification.md
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Windows temp and profile directories carry 8.3 names such as RUNNER~1, which
the plain-word guard refused, so lane next failed on the Windows leg. A tilde
after the first character is read literally by every shell.
Comment thread .dotf/lane-prompt.md Outdated
Comment on lines +1 to +13
Carril de fixes de dotfiles: bugs que descubren otros proyectos, sin bloquear los demás carriles. Regla: un bug = una rama fix/<slug> = un worktree = una PR. Nunca acumules bugs en una rama.

Tu bug: #{{.Number}} {{.Title}}. Este worktree ya existe, en la rama {{.Branch}}, creado desde origin/main.{{if .Remaining}} Detrás en la cola:{{range .Remaining}} #{{.}}{{end}}.{{end}} Si otro proyecto reporta un bug, entra en la cola (.dotf/lane.json) por prioridad.

Por bug: reproduce, escribe el test que falla, arregla, aplica mutación, `go build/vet/test`, `GOOS=windows go vet`, golangci-lint (el pin). Asígnate el issue al empezar. PR con label skip-sdd, "## SDD skip rationale" y "## Knowledge" (lesson nueva en docs/lessons, regenerada con `dotf lessons fmt`; coge el siguiente número libre mirando origin/main y las PRs abiertas). Draft, ready, triaje, `dotf pr land`.

Primer push de una rama sin PR: `SDD_LABELS=skip-sdd SDD_PR_BODY=... git push` (el spec-gate solo lee la PR cuando existe).

Cola de PRs entre sesiones: aterriza una a la vez y solo la cabeza de la cola actualiza su rama (dotf pr land rechaza BEHIND). Compruébalo con `gh pr list --state open`. Permiso de merge para PRs propias: coordinado con las otras sesiones, CI verde, sin conflictos y comentarios de reviewers atendidos. No toques las ramas ni las PRs de otros carriles.

Al aterrizar NO borres tu worktree (cierra tu pane y tu sesión). Haz /handoff, ejecuta `dotf lane next` para arrancar al sucesor y para.

Lee AGENTS.md antes de la primera herramienta. Responde en español; todo artefacto durable en inglés.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Harness compliance

Rule: English only in the durable record, including committed files and code comments. The committed prompt template is written in Spanish, and the PR title and body are English. REAL: the file is a durable artifact in the repo. Counter-argument: it is a runtime prompt rather than a comment, so this may be intentional, but the rule makes no such exception.

Comment thread specs/CLI-119-lane-next/proposal.md Outdated
---
id: "CLI-119-lane-next"
type: spec
status: draft # draft | implementing | verifying | archived

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Harness compliance

Rule: Definition of Done, Evidence/Review. The spec is still status: draft, the Closing and Archive checklists are unticked in tasks.md and verification.md, and the PR is described as one PR instead of the two planned. There is no visible ## Knowledge section or skip-sdd rationale in the (truncated) PR body. REAL for the unticked closing items; the PR body is truncated, so this part is uncertain.

Comment on lines +22 to +24
"pi": func(p string) []string {
return []string{"dotf", "secrets", "run", "--only", "NAN_API_KEY,OPENROUTER_API_KEY", "--", "pi", p}
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded dotf

REAL: the pi launcher uses the bare word dotf, which on the pane's PATH resolved to the pinned release that lacks lane. The PR fixes this for the outer command but not for the inner dotf secrets run. This works only because the pinned release has secrets run. The pi key list is also duplicated (#2534). Impact: low.

Comment on lines +73 to +75
if !plainWord.MatchString(promptFile) {
return out, fmt.Errorf("lane: the prompt path %q has characters a pane's shell would read differently; use a PromptDir of letters, digits and _ . / : \\ ~ -", promptFile)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible Issue

THEORETICAL: Handoff calls Fetch only on the create path. In the reuse path (found && !Open), Open runs against a possibly stale branch with no fetch. Also, the plainWord check rejects any prompt directory containing spaces. For a repo path with spaces, lane next fails outright instead of falling back (the no-backend commands path also prints unquoted paths).

Comment on lines +48 to +51
func (h Herdr) Available() bool {
_, err := h.herdr("pane", "current")
return err == nil
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backend detection

THEORETICAL: Available() treats any error from herdr pane current (for example a transient failure) as "no backend". The command then silently degrades to printing commands and writing the prompt, even when herdr is installed. In that case the --agent default also fails with a different message. Low impact.

@github-actions

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis ❌

2528 - Partially compliant

Compliant requirements:

  • Worktree creation through the repo parent
  • Launch table (claude, pi, agy) with unknown agent refused
  • Idempotent rerun
  • Backend interface has no remove method
  • No-backend fallback prints the commands
  • Queue in .dotf/lane.json
  • Fake backend tests

Non-compliant requirements:

  • Launch table covers only 3 of the 6 harnesses (declared out of scope)
  • Queue is a repo file, not a bitácora label
  • Parent process flags are not carried to the successor

Requires further human verification:

  • Real herdr and agent launches on macOS
  • Windows lane exec child-process path (not measured)

2534 - Not compliant

Non-compliant requirements:

  • The pi key list is copied into launch.go (the PR acknowledges this and defers it to this ticket)

2533 - Not compliant

Non-compliant requirements:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 PR contains tests
🔒 No security concerns identified

⚙️ Agent run details
  • Model: anthropic/claude-sonnet-5-5
  • Tokens: 59,047 in / 1,746 out / 60,793 total
  • Time cost: 19.5s
  • AI calls: 1

The lane file and its prompt template are read by dotf lane next, so a diff
that only touches them must not skip the tests.
@mlorentedev

Copy link
Copy Markdown
Owner Author

Review triage

Reviewers: PR-Agent (github-actions, 5 findings, head 3746c52f). CodeRabbit hit its free review limit and reviewed nothing.

Finding Disposition
pi launcher uses bare dotf for the inner secrets run Declined: secrets run exists in every release, including the pinned one, so it works; the whole inline call goes away with the wrapper unification in #2534.
Available() treats any pane current error as "no backend" Declined: outside herdr that command fails by design; a transient failure prints the commands with a notice and exits 0, never a wrong action.
Fetch only on the create path; prompt dir with spaces refused Fetch: declined, an existing worktree's branch must not be moved. Spaces: ticketed as #2537 (real on Windows paths with a space; the guard is deliberate and tested).
Prompt template in Spanish Applied: rewritten in English, the reply-language instruction kept inside it (e425cc3d..next push).
Spec still draft, closing items unticked Applied: status: verifying. The archive checklist stays open on purpose; it closes with the independent review, per the spec-close gate.
Ticket compliance: harness table covers 3 of 6, queue is a file, flags not carried Declined: declared out of scope in the spec.

Also fixed during CI: Windows short paths (RUNNER~1) were refused by the quoting guard (3746c52f), and .dotf/ was missing from the CI code filter (e425cc3d).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant