What to do when the desktop is busy: resource holders and queues
When another task already owns the desktop, GoWork should not cancel parallel work by default. This article explains how resource holders, desktop queues, and concurrent orchestration fit together, and why waiting in line is safer than grabbing the mouse.
Here is the short answer: when another run already owns the desktop, the safest default is usually not to cancel the old task and not to reject the new one, but to queue the desktop-dependent step. resource_holders tells the assistant which exclusive resource is currently owned by another run. The desktop queue makes sure multiple runs that need the same mouse, keyboard, and screen do not trample one another. For an execution-focused assistant, this is not a small scheduling detail. It is the difference between safe parallelism and chaotic interference.
That is why OmniGoAI’s GoWork separates task-level parallelism from desktop-level serialization. A system can keep many non-conflicting tasks moving at once: reading files, collecting evidence, drafting content, and preparing reports. But once an action needs the only physical desktop, it has to respect an exclusive boundary. A reliable assistant does not respond to a busy desktop with “do nothing.” It responds with a better rule: keep parallelizing the parts that can run in parallel, and queue the part that needs exclusive access.
If you have already read Status questions and stop commands are not the same and Why assistants should explain intent before tool actions, this article explains the neighboring orchestration boundary: why a reported desktop holder should trigger orderly waiting, not grabbing, retriggering, or accidental cancellation.
The short answer: resource holders expose contention, queues absorb it
A useful model has four parts:
resource_holdersreports a current exclusive fact, not a failure condition.- A busy desktop means later desktop actions must wait in line, not that the whole task must stop.
- Steps that do not need the desktop should continue in parallel as normal.
- The dangerous mistake is to read “the desktop is busy right now” as either “the new task cannot proceed” or “the old task must be cancelled.”
That boundary matters because it decides whether the system behaves like a coordinated parallel assistant or a pile of runs fighting over one physical surface.
What resource_holders is really telling you
It tells you who currently owns an exclusive resource
When the system reports a resource holder, the important information is:
- which resource is occupied;
- which other run currently owns it;
- whether the new action also needs that same resource.
For desktop work, the usual case is a single desktop holder. That makes sense because there is only one real mouse, one real keyboard, and one visible screen. If one run is clicking through a login flow while another tries to focus another window, type text, and take screenshots, the result is usually not speed. It is corruption of the scene.
It does not mean “treat this as a hard failure”
Immature systems often turn resource contention directly into a task error: the desktop is busy, so the new task fails. Or worse, the new task tries to look responsive by killing the old one first. That may feel aggressive and fast, but it pushes the scheduler’s job back onto the user.
A better use of resource_holders is to say: there is contention here, but contention is manageable. It is a report about the scene, not a reason to make a control decision on the user’s behalf.
Why desktop tasks cannot be parallelized like read-only tools
Because the desktop is not a copyable resource
Read-only operations such as file reads, web fetches, or status lookups are often naturally parallel:
- they are mostly read-only;
- they do not fight over one physical input surface;
- one observation usually does not destroy another operation’s context.
Desktop automation is different. It depends on shared global state:
- the foreground window;
- the cursor position;
- the currently focused control;
- the visible pixels on the screen.
Those are not isolated per run. They are shared and instantly mutable. Two desktop runs at once are not just “concurrent.” They are competing for the same scene.
Because desktop actions depend on context continuity
Desktop workflows are usually multi-step chains:
- open a window;
- wait for the page to load;
- find a button;
- click it;
- inspect the result.
If another run steals focus, switches windows, scrolls the page, or changes what is visible between steps 3 and 4, then the first run’s reasoning can collapse. Desktop contention is not just about timing. It breaks semantic continuity.
Why queuing is usually better than cancellation
Because resource conflict is not the same as goal conflict
A new task needing the desktop does not mean it conflicts with the current task’s purpose. Often they simply both need the same physical resource while pursuing different goals. For example:
- one task is logging into a creator backend;
- another wants to inspect a download page;
- a third is only reading files and drafting a report.
Only the first two have a desktop conflict, and even they do not have a business-level conflict. They merely need different turns on the same hardware. In that situation, the right default is to queue the later desktop action and let it continue once the earlier run releases the resource.
Because arbitrary cancellation breaks the user’s expected parallelism
When users rely on a resident assistant, they usually accept that non-conflicting work can keep moving in parallel. If the system reacts to every desktop holder by cancelling the new task or killing the old one, then internal scheduling cost becomes user-facing retry cost.
That creates two common losses:
- an almost-finished desktop run gets interrupted for no user-approved reason;
- a new task that only needed to wait a short while is incorrectly treated as impossible.
That is not healthy caution. It is overreaction.
What the queue actually solves
It turns simultaneous arrival into orderly entry
The queue’s core value is simple: it converts “multiple runs want the desktop now” into “multiple runs will enter the desktop one at a time.” That means:
- humans do not have to manually coordinate turns;
- the assistant does not need to cancel another run just to free the desktop;
- “cannot click right now” is no longer misread as “the goal cannot be completed.”
The system only needs to enforce one thing: at any given moment, only one run is actively driving the desktop. Once that line holds, multiple desktop tasks can complete in a predictable serialized order.
It preserves task-level parallelism while serializing only the conflicting step
This is the key idea: the thing that should be serialized is the resource-conflicting step, not the full lifetime of the task.
A long task may include:
- reading inputs;
- preparing content;
- waiting for its turn on the desktop;
- clicking through a visible flow;
- writing logs and reporting results.
Usually only step 4 truly needs exclusive desktop access. The reading, drafting, planning, and logging around it do not. A good system does not lock the whole task into one giant serialized block just because one segment needs the desktop.
The three most common mistakes
Mistake 1: a busy desktop means the new task cannot start
This is the most common misread. In reality, a new task can often still do a lot before it needs the desktop:
- parse the user intent;
- inspect files and current state;
- produce a plan;
- prepare data that will be used later.
Only when it reaches a truly desktop-dependent step does it need to wait. Rejecting the whole task from the beginning confuses “one step cannot run yet” with “the workflow cannot run at all.”
Mistake 2: a busy desktop means the current task should be cancelled
That does not follow either. Unless the user explicitly says to stop the current run, the system has no reason to kill it just to make room. Resource contention is a scheduling problem. It should not silently escalate into a control decision.
If every new desktop request can displace the previous one, the system does not really support concurrency. It supports constant interruption.
Mistake 3: having a queue means the system is not parallel
This is another common misunderstanding. A genuinely parallel system does not require every step to execute at once. It means parallelize what can be parallelized, and serialize only the segment that truly must be exclusive. The desktop queue exists because the physical world has exclusive boundaries, not because the system has given up on concurrency.
What good user-visible feedback looks like
When another run is currently holding the desktop, the best user-facing status usually says three things:
- the desktop is currently occupied by another task;
- this new desktop step is queued and will start automatically afterward;
- non-conflicting preparation work can still continue meanwhile.
That kind of answer matters because it does not create the false impression of failure, and it does not pretend immediate execution either. It reports the real state: queued, not abandoned.
A safer decision order
When a new task contains desktop work, a stable handling order looks like this:
- identify which steps truly need the desktop;
- inspect
resource_holdersto see whether another run owns it; - keep doing the read-only and preparation steps that do not conflict;
- when the task reaches the actual desktop step, let the queue serialize it;
- continue once the earlier run releases the resource;
- only enter a cancellation path if the user explicitly asks to stop a task.
The point of this order is that it keeps resource coordination separate from task control. As long as those remain separate, a temporary exclusive conflict is much less likely to turn into a broken workflow.
Why this boundary directly affects user trust
Most users do not care whether the system has an internal queue. They care about two visible outcomes:
- will my new task get ignored because another task is using the desktop;
- will my current task get interrupted just because a new message arrived.
If the system reliably queues the new desktop action without dropping it, and lets the current task finish without arbitrary interruption, users quickly form the right expectation: this assistant can juggle multiple tasks without fighting over the mouse. For a long-running assistant like GoWork, that expectation matters far more than the illusion of many windows moving at once.
You can try that orchestration model on the GoWork download page. If you want the adjacent coordination topics, also read Status questions and stop commands are not the same and Why assistants should explain intent before tool actions.
FAQ
FAQ 1: If the desktop is busy, should the assistant stop doing everything?
No. Many preparation steps do not need the desktop at all, such as reading files, gathering parameters, checking state, and drafting content. The part that should wait is only the mouse-keyboard-screen segment, not the entire task.
FAQ 2: If the new task is more urgent, should the system automatically preempt the desktop?
Not by default. Whether to interrupt the current run is a control decision, not something that should be inferred automatically from contention. Unless the user explicitly asks to stop or redirect the current task, queueing is the safer default.
FAQ 3: Does a desktop queue reduce parallelism?
No. It only serializes the desktop-conflicting segment. Read-only work, planning, web lookups, drafting, and reporting can still progress in parallel where appropriate.
FAQ 4: How do resource_holders and the queue divide responsibilities?
Think of them as an observation layer and an execution layer. resource_holders answers “who owns the exclusive resource right now?” The queue answers “how should the next desktop action enter safely?” The first reports the present state; the second turns that state into orderly execution.