{"slug": "my-two-ai-tasks-kept-fighting-for-the-same-mouse", "title": "\"My Two AI Tasks Kept Fighting for the Same Mouse\"", "summary": "A developer building CliGate, an open-source local control plane for AI assistants, encountered a concurrency bug when multiple AI tasks tried to control the same mouse, keyboard, and screen on Windows. The solution was to treat the desktop as a queueable resource, serializing tasks that need exclusive access while allowing non-desktop tasks to run in parallel. This approach prevents collisions and makes the assistant behave more like a human operator.", "body_md": "The second my local AI assistant learned how to operate Windows apps, I ran into a new bug.\n\nNot a model bug. Not a prompt bug.\n\nA traffic bug.\n\nOne task was logging into a site through the desktop. Another task wanted to open a different app. Both requests were valid. Both were \"in progress.\" And both were trying to use the same physical mouse, keyboard, and screen.\n\nThat is when an assistant stops feeling like software and starts feeling like two interns fighting over one laptop.\n\nIn CliGate, I already had the shape of a resident assistant: background runs, task records, channel conversations, runtime delegation, and desktop automation on Windows.\n\nThe problem was that \"multiple tasks\" and \"multiple desktop tasks\" are not the same thing.\n\nMost work can run in parallel just fine. A coding task can edit files while another task checks the weather or summarizes a document. But desktop control is a physical boundary. There is only one active pointer, one focused window, one keyboard target.\n\nIf the system treats every run as equally parallel, desktop tasks do not feel concurrent. They feel destructive.\n\nOne can steal focus. Another can click into the wrong window. A third can decide there is already a similar run and cancel the wrong thing entirely.\n\nThe old mental model was too shallow:\n\n``` php\nconversation -> active runs -> decide whether to cancel one\n```\n\nThat can work for status displays. It is not enough for desktop scheduling.\n\nWhat I actually needed was a separate truth the assistant could look at:\n\n```\nresource: desktop\nholder: run X\nwaiters: run Y, run Z\n```\n\nThat changed the question from:\n\ninto:\n\nThat is a much more useful question.\n\nI ended up moving toward a simple rule set.\n\nIf two tasks do not need the same exclusive resource, let them run in parallel.\n\nIf they both need the desktop, serialize them.\n\nIf the user asks for status, answer from the existing run instead of touching the desktop again.\n\nIf the user says \"stop,\" cancel the target run explicitly.\n\nThat sounds obvious in hindsight, but it changed the behavior a lot.\n\nInstead of seeing another run and trying to kill it, the assistant can now treat the desktop like a queueable resource. One task holds it. The next desktop task waits. When the holder finishes, the next one starts automatically.\n\nThat is much closer to how a human assistant would behave. You would not cancel a login flow just because someone also asked you to open another app. You would say: \"I'm in the middle of this one, I'll do the next desktop step right after.\"\n\nThe nice side effect is that the assistant becomes easier to talk to during long tasks.\n\nWhile a desktop job is running, I can still ask:\n\nThose should not all be treated as reasons to interrupt the desktop flow.\n\nThe assistant can answer status questions from run state, do non-desktop work in parallel, and only queue the things that truly need the same physical controls.\n\nThat made the product feel less like a brittle automation demo and more like an actual operator with limited hands.\n\nIf an agent can touch the real desktop, it needs to understand the difference between:\n\nWithout that split, concurrency just becomes another word for collision.\n\nThat is now part of how I am shaping CliGate, the local control plane I use for Claude Code, Codex CLI, Gemini CLI, channels, desktop automation, and a resident assistant layer on top.\n\nThe project is open source here: [CliGate](https://github.com/codeking-ai/cligate).\n\nIf you are building local agents, are you treating the desktop as just another tool call, or as a resource that needs scheduling?", "url": "https://wpnews.pro/news/my-two-ai-tasks-kept-fighting-for-the-same-mouse", "canonical_source": "https://dev.to/codekingai/my-two-ai-tasks-kept-fighting-for-the-same-mouse-17m5", "published_at": "2026-06-16 12:02:21+00:00", "updated_at": "2026-06-16 12:17:36.585689+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-infrastructure"], "entities": ["CliGate", "Claude Code", "Codex CLI", "Gemini CLI", "Windows"], "alternates": {"html": "https://wpnews.pro/news/my-two-ai-tasks-kept-fighting-for-the-same-mouse", "markdown": "https://wpnews.pro/news/my-two-ai-tasks-kept-fighting-for-the-same-mouse.md", "text": "https://wpnews.pro/news/my-two-ai-tasks-kept-fighting-for-the-same-mouse.txt", "jsonld": "https://wpnews.pro/news/my-two-ai-tasks-kept-fighting-for-the-same-mouse.jsonld"}}