Skip to content

fix(projects): deliver the first-turn prompt for headless-created projects - #410

Merged
jrothrock merged 2 commits into
mainfrom
fix/headless-project-start-prompt
Sep 11, 2026
Merged

jrothrock merged 2 commits into
mainfrom
fix/headless-project-start-prompt

Conversation

@jrothrock

Copy link
Copy Markdown
Collaborator

The bug (conv 160 / 162)

When the conductor creates a project via the API and starts it, the sandbox's Claude comes up to an idle TUI and never starts working — activity stuck at waiting, anthropic_hits=0. The whole "conductor routes code work into a sandbox" flow is broken end-to-end for anything it creates itself.

Two root causes:

  1. The create body had no prompt field — yet the corral-api skill documents POST /projects/create -d '{"prompt":"..."}' and promises it's auto-submitted. The backend silently dropped it. The conductor passed the task in prompt; it went nowhere.

  2. Prompt delivery was browser-driven only. The UI calls POST /p/<id>/populate-prompt after create to type the prompt into Claude's tmux pane. Headless callers have no browser → nothing delivered it. (And the container often wasn't even launched with tmux, so there was no pane to send to.)

The fix

  • Honor prompt on create: persisted as the project's PendingPrompt, overriding the generic project.start template when provided.
  • Auto-deliver on start: handleStartProject types the pending prompt into Claude's pane and submits it — no browser needed.
  • Force tmux when a prompt is pending: delivery needs the tmux pane, so create sets LaunchTmux=true in that case (otherwise the launcher runs a bare interactive claude with no pane → idle forever).
  • Fire-once: claimPendingPrompt atomically reads-and-clears under a mutex, so the browser's concurrent /start + /populate-prompt can't double-type the task, and a restart won't re-inject it. The tmux send logic is extracted into deliverPromptToClaude, shared by both paths.
  • Skill doc: spell out create → start → auto-submit so the conductor doesn't leave a project idle.

Tests

claimPendingPrompt: fire-once, 16-way concurrent (exactly one winner, -race clean), missing/empty config. Full internal/dashboard + internal/config build & pass.

🤖 Generated with Claude Code

jrothrock and others added 2 commits September 11, 2026 12:42
…jects

A project created via the API by the conductor (no browser) came up to an
idle Claude TUI and never started working (conv-160): activity stuck at
`waiting`, anthropic_hits=0. Two root causes:

1. The create body had no `prompt` field, yet the corral-api skill documents
   `POST /projects/create -d '{"prompt":"..."}'` and promises it's auto-
   submitted. The backend silently dropped it. Now honored: a caller prompt
   is persisted as the project's PendingPrompt and overrides the generic
   project.start template.

2. Prompt delivery was BROWSER-driven only — the UI calls POST /populate-prompt
   after create. Headless callers have no browser, so nothing delivered it.
   Now the backend auto-delivers on start (handleStartProject): if a
   PendingPrompt exists it types it into Claude's tmux pane and submits.
   Delivery requires tmux, so create forces LaunchTmux whenever a prompt is
   pending (else the launcher runs a bare interactive claude with no pane to
   send-keys into — the idle-forever failure).

Delivery is fire-once via claimPendingPrompt (atomic read-and-clear under a
mutex), so the browser's concurrent /start + /populate-prompt can't double-
type the task, and a later restart won't re-inject it. The tmux send logic
is extracted into deliverPromptToClaude, shared by both paths.

Tests: claimPendingPrompt fire-once + 16-way concurrent (exactly one winner,
-race clean) + missing/empty config.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ompts

The corral-api skill implied /projects/create alone starts Claude on the
task. It doesn't — you must POST /p/<id>/start, which now auto-delivers the
prompt. Spell out the two-step flow so the conductor doesn't leave a project
idle (the conv-160 confusion).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jrothrock
jrothrock merged commit 70ee710 into main Sep 11, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant