Skip to content

fix: wait for agent prompt readiness - #2537

Merged
ogulcancelik merged 6 commits into
herdrdev:masterfrom
Pimpmuckl:issue/2410-agent-start-trust-readiness
Aug 11, 2026
Merged

fix: wait for agent prompt readiness#2537
ogulcancelik merged 6 commits into
herdrdev:masterfrom
Pimpmuckl:issue/2410-agent-start-trust-readiness

Conversation

@Pimpmuckl

@Pimpmuckl Pimpmuckl commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

What changed

herdr agent start now follows the detector's public state instead of treating process recognition as readiness. A newly recognized agent starts as Unknown during detection acquisition. Idle completes startup, Blocked returns agent_not_ready immediately, and Working or Unknown keep waiting until the caller's timeout.

A blocked managed agent keeps its name, so callers can inspect it with agent read and answer setup prompts with agent send-keys. If detection later reports Idle, the existing named agent becomes ready for agent prompt.

Codex detection now classifies the live Trust this directory screen as Blocked, including the compact wrapped layout, without matching copied trust text in conversation history. The first Idle after process acquisition is treated as startup readiness rather than completed work, including in headless notification forwarding.

Why

agent start previously treated a detected Idle or Blocked state as equivalent to proof that the agent's normal input prompt was visible after the settle window. Process detection also published a temporary Idle and skipped screen scans for the same three-second acquisition window, so startup could complete before Herdr classified the actual screen.

The concrete #2410 reproduction is Codex showing its first-run Trust this directory prompt. Herdr returned interactive_ready: true before the normal Codex prompt was visible, so an immediate agent prompt could be sent before Codex was ready.

With this change, the trust screen returns agent_not_ready instead. Once trust is accepted and Codex reaches its normal Idle prompt, the named agent becomes ready for prompts.

Agent coverage

The startup policy is agent-independent: Idle is ready, Blocked is not ready, and Working or Unknown continue waiting. Accurate readiness still depends on each agent's detector classifying its live screen correctly. This PR adds the missing Codex trust-screen rule required for #2410.

Validation

  • reproduced the Codex trust screen on Windows, including the compact seven-row layout
  • added detector coverage for live and transcript trust text
  • added managed-start coverage for Unknown, Blocked, and later Idle transitions
  • added CLI transport coverage for immediate agent_not_ready
  • added app and headless coverage preventing startup readiness from producing completion notifications
  • just check with Rust tests serialized

The Windows media-player test is quite flaky in the parallel batch. It passed alone and in the serialized full check. Might be worth a follow-up fix eventually.

refs #2410

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Agent detection now initializes new agents as unknown and emits a dedicated process-detection event. Codex trust prompts enter a blocked state. Managed launches remain pending until idle detection. CLI startup returns agent_not_ready for blocked agents, with tests and documentation updated.

Changes

Managed-agent blocked startup

Layer / File(s) Summary
Detection initialization and Codex blocker rules
src/events.rs, src/pane.rs, src/terminal/state.rs, src/detect/manifests/codex.toml, website/agent-detection/codex.toml, src/detect/manifest/tests.rs
New detections start as unknown and publish AgentProcessDetected. Codex directory-trust prompts are detected as visible blockers.
Blocked managed-agent reconciliation
src/terminal/state.rs
Blocked launches remain pending without deadlines, preserve their names, activate on matching idle detection, and clear after process exit.
Process acquisition and completion handling
src/app/actions.rs
Managed launches suppress the initial idle completion notification. Later process-exit completions remain observable.
CLI startup contract and validation
src/cli/agent.rs, tests/cli/agent_transport.rs, docs/next/website/src/content/docs/...
Blocked startup returns agent_not_ready. Tests and English, Japanese, and Chinese documentation describe addressability until idle readiness.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Detector
  participant AppEvent
  participant TerminalState
  participant PaneState
  participant AgentCLI
  Detector->>AppEvent: publish AgentProcessDetected
  AppEvent->>TerminalState: begin process acquisition
  Detector->>TerminalState: report blocked state
  TerminalState->>PaneState: retain pending launch and suppress initial completion
  AgentCLI->>TerminalState: poll startup state
  TerminalState-->>AgentCLI: return agent_not_ready
  Detector->>TerminalState: report matching idle state
  TerminalState-->>AgentCLI: report interactive readiness
Loading

Possibly related PRs

Suggested labels: coderabbit-review

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.91% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The description clearly explains the readiness, blocked-state, detection, Codex, testing, and notification changes in the pull request.
Title check ✅ Passed The title clearly summarizes the main change: agent startup now waits for prompt readiness before completing.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@kangal-bot kangal-bot added the ai-review Trigger automated AI reviews for pull requests admitted by the PR gate label Aug 9, 2026
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/terminal/state.rs (1)

1816-1945: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Activation gating correctly separates fallback agents from positive-idle-rule agents.

begin_managed_agent seeds prompt_ready/allow_blocked from require_visible_idle, and reconcile_managed_agent_at requires prompt_ready (or live full-lifecycle hook authority) for Idle activation, and allow_blocked for Blocked activation. This matches the objective that generic initial Idle/Blocked states no longer indicate readiness for agents with a positive idle rule, while agents without one keep existing fallback behavior.

Consider adding a short doc comment above ManagedAgentPhase::Pending explaining what prompt_ready and allow_blocked represent and how require_visible_idle seeds them, since the interaction between these two flags and the manifest rule is not obvious from the field names alone.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 42cbfeaa-aa3d-4d81-9c2c-1581a4c35972

📥 Commits

Reviewing files that changed from the base of the PR and between 1777e9b and 1996ced.

📒 Files selected for processing (12)
  • src/app/actions.rs
  • src/app/agents.rs
  • src/app/api.rs
  • src/app/api/agents.rs
  • src/app/input/mouse.rs
  • src/app/mod.rs
  • src/detect/manifest.rs
  • src/events.rs
  • src/pane.rs
  • src/persist/snapshot.rs
  • src/server/headless.rs
  • src/terminal/state.rs

@Pimpmuckl
Pimpmuckl force-pushed the issue/2410-agent-start-trust-readiness branch from 1996ced to f09eeac Compare August 9, 2026 00:38
@Pimpmuckl

Copy link
Copy Markdown
Contributor Author

🧹 Nitpick comments (1)

src/terminal/state.rs (1)> 1816-1945: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Activation gating correctly separates fallback agents from positive-idle-rule agents.
begin_managed_agent seeds prompt_ready/allow_blocked from require_visible_idle, and reconcile_managed_agent_at requires prompt_ready (or live full-lifecycle hook authority) for Idle activation, and allow_blocked for Blocked activation. This matches the objective that generic initial Idle/Blocked states no longer indicate readiness for agents with a positive idle rule, while agents without one keep existing fallback behavior.
Consider adding a short doc comment above ManagedAgentPhase::Pending explaining what prompt_ready and allow_blocked represent and how require_visible_idle seeds them, since the interaction between these two flags and the manifest rule is not obvious from the field names alone.

Sure, why not, added the comment in f09eeac

@greptile-apps

greptile-apps Bot commented Aug 9, 2026

Copy link
Copy Markdown

Greptile Summary

This PR makes managed agent startup wait for positive prompt-ready evidence when supported, while preserving fallback behavior for agents without such evidence.

  • Separates process acquisition from confirmed idle readiness.
  • Treats blocked startup as immediately not ready while retaining the managed agent name.
  • Publishes readiness-only updates and suppresses false startup completion notifications.
  • Adds Codex trust-directory detection and updates CLI behavior, tests, and documentation.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
src/terminal/state.rs Introduces blocked managed-launch state, positive-evidence readiness reconciliation, and acquisition-completion suppression.
src/pane.rs Publishes process acquisition separately from screen-confirmed state and initializes new detections as unknown.
src/app/actions.rs Reconciles managed readiness on state updates and suppresses startup idle transitions from completion effects.
src/server/headless.rs Propagates completion suppression through headless notification forwarding.
src/cli/agent.rs Waits through unknown or working startup states and returns agent_not_ready for blocked launches.
src/detect/manifests/codex.toml Adds top-region detection for Codex's trust-directory prompt and advances the manifest engine requirement.
tests/cli/agent_transport.rs Updates transport coverage for unknown, blocked, and ready startup responses.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Agent process detected] --> B[Record Unknown acquisition state]
  B --> C{Positive prompt evidence available?}
  C -->|Yes| D[Wait for visible idle evidence]
  C -->|No| E[Use existing fallback readiness]
  D --> F{Detected state}
  F -->|Blocked| G[Return agent_not_ready]
  F -->|Idle after settle| H[Mark interactive ready]
  F -->|Working or Unknown| I[Remain launch pending]
  E --> H
  H --> J[Publish readiness update]
  G --> K[Retain agent name for read and send-keys]
Loading

Reviews (11): Last reviewed commit: "Merge branch 'master' into issue/2410-ag..." | Re-trigger Greptile

Comment thread src/terminal/state.rs
@greptile-apps

greptile-apps Bot commented Aug 9, 2026

Copy link
Copy Markdown

Want your agent to iterate on Greptile's feedback? Try greploops.

@ogulcancelik ogulcancelik left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

i feel like a better approach would be to keep startup readiness based on the detection engine’s public state instead of making agent start inspect manifest details.

if detection reports blocked, startup should never set interactive_ready: true. ideally it should return immediately with a blocked/not-ready result rather than waiting for the 30-second timeout (we can also lower it to 10 imo 30 feels long). idle succeeds, while unknown keeps waiting.

if the codex trust screen is not reliably classified as blocked—or falls back to idle—that seems like a detection problem we should fix there. this would be smaller and keep visible_idle as detector evidence rather than turning it into startup policy.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
src/server/headless.rs (1)

11064-11068: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider covering handle_internal_event_with_pane_updates in the bypass guard test.

The guard test only matches self.app.handle_internal_event( and self.app.handle_internal_event_with_prefix_sync(. The forwarding method now also uses self.app.handle_internal_event_with_pane_updates(. A future direct call to that method outside handle_internal_event_with_forwarding would bypass forwarding without failing this test.

♻️ Proposed guard extension
             } else if (line.contains("self.app.handle_internal_event(")
-                || line.contains("self.app.handle_internal_event_with_prefix_sync("))
+                || line.contains("self.app.handle_internal_event_with_prefix_sync(")
+                || line.contains("self.app.handle_internal_event_with_pane_updates("))
                 && !line.trim().starts_with("///")
                 && !line.contains("contains(")
tests/live_handoff.rs (1)

1477-1497: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Bound the marker-file wait loops in the helper scripts.

Both scripts spin on while [ ! -f ... ]; do sleep 0.01; done with no upper bound. If the counterpart process never creates its marker, for example when server.live_handoff fails before spawning the importer, the script spins until the test harness terminates it. A bounded loop turns that case into a fast, diagnosable failure instead of a busy spin.

♻️ Proposed bounded waits
     fs::write(
         &fake_codex,
         "#!/bin/sh\n\
          exec env HERDR_AGENT=codex /bin/sh -c '\n\
            printf \"\\033[2J\\033[H> You are in /tmp\\n\\n  Do you trust the contents of this directory?\\n\"\n\
            touch \"$HERDR_TEST_AGENT_STARTED\"\n\
-           while [ ! -f \"$HERDR_TEST_IMPORTER_STARTED\" ]; do sleep 0.01; done\n\
+           i=0\n\
+           while [ ! -f \"$HERDR_TEST_IMPORTER_STARTED\" ] && [ \"$i\" -lt 3000 ]; do sleep 0.01; i=$((i+1)); done\n\
            touch \"$HERDR_TEST_AGENT_EXITED\"\n\
          '\n",
     )
     .unwrap();
     fs::write(
         &import_wrapper,
         "#!/bin/sh\n\
          touch \"$HERDR_TEST_IMPORTER_STARTED\"\n\
-         while [ ! -f \"$HERDR_TEST_AGENT_EXITED\" ]; do sleep 0.01; done\n\
+         i=0\n\
+         while [ ! -f \"$HERDR_TEST_AGENT_EXITED\" ] && [ \"$i\" -lt 3000 ]; do sleep 0.01; i=$((i+1)); done\n\
          exec \"$HERDR_TEST_HERDR_EXE\" \"$@\"\n",
     )
     .unwrap();

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ed86ff94-d654-4ecc-af8b-ed300f76d16c

📥 Commits

Reviewing files that changed from the base of the PR and between f09eeac and b42fd4b.

📒 Files selected for processing (23)
  • docs/next/website/src/content/docs/agent-automation.mdx
  • docs/next/website/src/content/docs/cli-reference.mdx
  • docs/next/website/src/content/docs/ja/agent-automation.mdx
  • docs/next/website/src/content/docs/ja/cli-reference.mdx
  • docs/next/website/src/content/docs/zh-cn/agent-automation.mdx
  • docs/next/website/src/content/docs/zh-cn/cli-reference.mdx
  • src/app/actions.rs
  • src/app/agent_resume.rs
  • src/app/agents.rs
  • src/app/api.rs
  • src/cli/agent.rs
  • src/detect/manifest/tests.rs
  • src/detect/manifests/codex.toml
  • src/events.rs
  • src/pane.rs
  • src/persist/restore.rs
  • src/persist/snapshot.rs
  • src/server/headless.rs
  • src/terminal/runtime.rs
  • src/terminal/state.rs
  • tests/cli/agent_transport.rs
  • tests/live_handoff.rs
  • website/agent-detection/codex.toml

Comment thread src/detect/manifests/codex.toml Outdated
Comment thread src/server/headless.rs
Comment thread src/terminal/state.rs
@Pimpmuckl
Pimpmuckl force-pushed the issue/2410-agent-start-trust-readiness branch 2 times, most recently from e471cab to 4bfd61c Compare August 9, 2026 13:05

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: df92ee09-234d-46b0-a32c-2fb31078f049

📥 Commits

Reviewing files that changed from the base of the PR and between e471cab and 4bfd61c.

📒 Files selected for processing (4)
  • src/app/actions.rs
  • src/events.rs
  • src/pane.rs
  • src/terminal/state.rs

Comment thread src/app/actions.rs
@Pimpmuckl
Pimpmuckl force-pushed the issue/2410-agent-start-trust-readiness branch from 4bfd61c to 28c4a9b Compare August 9, 2026 13:55
@Pimpmuckl

Copy link
Copy Markdown
Contributor Author

Thanks, yep agreed. I reworked this around the detector's public state.

The race was earlier than startup policy. Process detection published a temporary Idle, then skipped screen scans for the same three seconds used as the startup settle window. Startup could therefore complete before detection had classified the actual screen.

When Herdr sees the process now, it publishes the agent identity as Unknown during that grace period. Idle succeeds, Blocked returns agent_not_ready immediately while keeping the name usable, and Working or Unknown keep waiting.

The first live Idle after process acquisition means ready, not completed work. A process exit still counts as completion, and later Unknown to Idle transitions for the same known agent keep their existing completion behavior. The same suppression now reaches the headless notification path, so sound and toast forwarding follow the same rule.

I also reproduced the Codex trust screen, including the compact seven-row layout. The detector now anchors on the live header and question, handles wrapping, and does not match trust text copied into a conversation.

This removes the manifest introspection and visible_idle startup policy from the previous version.

I also looked at 30s vs 10s. We do not currently record enough startup timing data to have super strong data. The detector already spends a fixed three seconds in acquisition grace, so 10 seconds leaves roughly seven seconds for the agent itself to start and reach a known state. So to me 10s sounds a bit too tight.

Now that Blocked returns immediately, the 30-second wait only applies while detection is still Working or Unknown. Callers that want faster failure can already use --timeout 10000. So I kept 30s overall, but can be tightened down eventually.

@Pimpmuckl
Pimpmuckl requested a review from ogulcancelik August 9, 2026 17:04
@ogulcancelik

Copy link
Copy Markdown
Collaborator

ty!

@ogulcancelik
ogulcancelik merged commit 7ae4b05 into herdrdev:master Aug 11, 2026
8 checks passed
@kangal-bot kangal-bot removed the ai-review Trigger automated AI reviews for pull requests admitted by the PR gate label Aug 11, 2026
@Pimpmuckl
Pimpmuckl deleted the issue/2410-agent-start-trust-readiness branch August 11, 2026 00:27
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.

3 participants