Repository navigation
feat(autopilot): Autopilot is configured in Settings and waits out plan limits - #279
Merged
Merged
Conversation
…an limits - Settings › AI › Autopilot: a hub page built from the Autopilot:* descriptors (Decided by, Each ticket runs as, and six bounded new settings: MaxParallel, MaxParallelTests, MaxFixRounds, MaxAgentRetries, ChecksTimeoutMinutes, ChecksPollSeconds), plus the fixed rules in plain words. Found by Ctrl+K; Board › Autopilot links to it. - The bounds are read per pass / per call; AutopilotPlanner stays pure and takes them as an AutopilotLimits parameter. The acceptance-run gate honours the cap per member's computer (RunGate) instead of one global semaphore. - One fix-round counter: the persisted RemoteSessionEntity.FixRounds. The step-by-step path reads it (the in-memory _fixRounds is gone) and a ticket's MAF flow seeds TicketFlow.Round from it, so the configured max is the true total across engines and restarts. - Plan limits: the RemoteAgent provider detects a Claude/Codex plan limit in the runner's reply (PlanLimitDetector, reset time when parseable) and raises a typed PlanLimitException + records the member's wait (IPlanLimits). Autopilot then starts nothing, retries nothing and spends no fix round until reset +1 min, logs one plain line, shows it on Board › Autopilot and Computers, and resumes the cut-short work (ResumeTask). A follow-up cut short by the limit is restored to where it stood and its fix round is taken back. - Board copy renders the live values and the real merge rule (green checks + review approved + acceptance passed on a connected computer). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018WAdQ7Rm24xss5QDSvXtJB
1 of 2 tasks
hoangsnowy
added a commit
that referenced
this pull request
Oct 24, 2026
AgentOs.Web opted out of TreatWarningsAsErrors (since the 2026-05 rename), so analyzer warnings piled up there while the rest of the solution enforced them. #279 cleared the backlog; the Web project now builds with 0 warnings, so the opt-out goes. Claude-Session: https://claude.ai/code/session_018WAdQ7Rm24xss5QDSvXtJB Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 of 2 tasks
hoangsnowy
added a commit
that referenced
this pull request
Oct 24, 2026
Pushed settings-autopilot (new, #279) and replaced agent-profiles, settings-prompts (#278) and board-autopilot (#279) in the AgentOS.NET Design System project. Claude-Session: https://claude.ai/code/session_018WAdQ7Rm24xss5QDSvXtJB Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
6 of 10 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Change description
Autopilot is now configured from the desktop, and it does what its screen says.
1. Constants are now settings (ADR-0011,
AutopilotSettingsinModules.Pipeline, tenant scope, read on every pass or call):Autopilot:MaxParallel(Tasks at once)Autopilot:MaxParallelTests(Acceptance tests at once, per computer)Autopilot:MaxFixRounds(Automatic fix rounds)Autopilot:MaxAgentRetries(Orchestrator retries)Autopilot:ChecksTimeoutMinutesAutopilot:ChecksPollSecondsAutopilotPlanneris still pure. The caps reach it as anAutopilotLimitsparameter, andAutopilotSettings.ReadLimitsAsyncclamps every stored value to its range. The acceptance-run cap used to be one globalSemaphoreSlim(1). It is now a keyedRunGate, one per member's computer, whose capacity is read each time a run asks for it.2. Settings → AI → Autopilot page (
AutopilotSettingsApp.razor). It is built fromSettingsFields,Panel,page-headandprefs-*, using tokens only. It has one new class,.autopilot-rules, defined inapp.css. The page is registered inSettingsHuband inSettingsSearch/SettingsLinks, so Ctrl/⌘+K finds "fix rounds", "decided by" and "autopilot". For admins, Board › Autopilot now has an Autopilot settings button. Members see a line saying an admin sets these values.3. Board copy shows live values and the real rule. It now reads "start approved tickets in order, three at a time … (up to 3 rounds per task)". Build and merge reads: "once its checks are green, the Reviewer agent approved it and the Testing agent passed it on your connected computer". The log line written when Autopilot is switched on was corrected too.
4. One fix-round counter.
ProjectOrchestrator._fixRounds(kept in memory) is gone. The step-by-step path reads the persistedRemoteSessionEntity.FixRounds. A ticket's MAF flow now starts itsTicketFlow.Roundfrom the same number (TicketWorkflowRunner.Seed) and caps atTicketFlow.MaxRounds. Agent retries no longer reset the rules' rounds. The worst case is nowMaxFixRounds + MaxAgentRetriestries in total, across engines and restarts. Before, it was about 3+3+2.5. Plan limits.
PlanLimitDetector(inModules.RemoteAgent, using source-generated regex) reads the tail of a runner reply. It reads a clean reply only when the reply is short. It handles:You've hit your session limit · resets 11:50pm (Asia/Ho_Chi_Minh)usage limit reached|<epoch>try again in 2 hours 5 minutesRemoteAgentLlmClientthrows a typedPlanLimitException(anLlmException, so existing catches keep working). It also records the member's wait inIPlanLimits(PlanLimitTracker): reset + 1 minute, or 30 minutes when no time is given.ProjectOrchestratorstarts nothing, retries nothing and sends nothing back.PlanLimitPauselogs one line when the wait starts ("Your computer's Claude plan hit its limit — Autopilot waits until 23:50, nothing is lost.") and one when it ends. The wait is checked again after the Orchestrator agent decides, and the "agent couldn't decide → rules" fallback is skipped while a plan is limited.TicketWorkflowpauses with a new stage,PlanLimited, before or after an agent step, without spending a round.BoardTaskServiceputs the change back to where it stood (its checks and findings are kept) and callsDecrementFixRoundsForTenantAsync. A first attempt that is cut short stays Failed with the CLI's text, and is not counted as stuck work for the Orchestrator agent.ResumeTaskmove restarts that work plainly, so no fix round is used.plan-limitkind.Also fixed: the analyzer warnings in the Web files this PR touches (CA2016 ×10, CA1834 ×3, CA1068, CA1001, CS8619, IDE0004). Web builds with
TreatWarningsAsErrors=false, so these had been piling up there.Docs:
docs/CONFIG.mdhas a new Settings → Autopilot section.docs/plans/autonomy-levels.mdis updated, with a new 4b for plan limits. README anddesign-system.mdare updated for the new rail entry.Not touched:
LlmClientFactory,LlmCallScope,OfflineLlmClient,FailoverLlmClient, the Review/Acceptance/AutopilotOrchestrator/Retrospective/IssueWork agent internals, AgentProfiles/AgentSettings, PromptCatalog and InsightsApp.Type of change
Related issues
Autopilot audit: hard-coded caps, no Settings › Autopilot page, static Board copy, three separate fix-round counters, and plan limits that burned retries.
Checklist
dotnet buildpasses locally in Release mode.dotnet build AgentOs.slnx -c Release --no-incrementalgives 0 errors. The only warning is the existingASPIRE010frominfra/AgentOs.AppHost(AspireUseCliBundle=false), which this PR doesn't touch.dotnet test --solution AgentOs.slnx -c Release: 1678 total, 0 failed (78 skipped, all env-gated E2E/lab tests).Test plan
Unit tests (new):
PlanLimitTests: detection on real-shaped strings, including resets that roll over to tomorrow or next year, the "exit N:" prefix, epoch, Codex durations, no zone, negatives, and the clean-reply length guard. Also the tracker's wait (reset + 1 min), isolation per member and per tenant, and the provider throwingPlanLimitExceptionand recording the wait.AutopilotConfigurationTests: descriptors, ranges and defaults;ReadLimitsAsyncdefaults and clamping;RetriesLeftwith the configured budget; the pause logging once at start and once at end;CutShortByPlanLimit;RunGatecap per computer.AutopilotPlannerTests: the configured slots, fix rounds and acceptance cap;WithinCapslimits; cut-short work resumes first, within the slots.TicketWorkflowTests: rounds seeded from the persistedFixRounds(persisted 2 + cap 3 = exactly one round left); the configured max; the plan limit pausing the flow without spending a round, including before the first step.TaskFailureTests,SettingsSearchTests: new cases.E2E (Playwright, standalone Web): new
AutopilotSettingsTests, 3/3 passed. It checks that every setting renders with its default, and that the merge and plan-limit rules are stated. It savesTasks at once= 99 (rejected, and the reason names the bound 6), then 3 (shows "This tenant"), then resets in afinally. Ctrl+K "fix rounds" opens the page.SettingsSearchTests,PlatformSettingsTestsandBoardTabsTestsstill pass.In the running app (screenshots taken locally, not committed):
AgentOs.RemoteAgent, configured through environment variables only, nothing saved) was paired to that Web. Its CLI was a stand-in script that printsYou've hit your session limit - resets 11:50pm (Asia/Ho_Chi_Minh)and exits 1. Force provider was set to RemoteAgent, and Board › New idea was triggered. The Web logged "the member's Claude plan hit its limit (resets 23:50)". The next Autopilot pass wrote the single wait line toworkspaces.autopilot_events.Not verified here: a real Claude/Codex plan limit on the lab server, and an actual resume after a real reset. Both need a used-up subscription. The resume path is covered by the planner and flow tests.
🤖 Generated with Claude Code
https://claude.ai/code/session_018WAdQ7Rm24xss5QDSvXtJB