AI agent assistants on your device — they plan, write, and run Python, and every step stays in the conversation.
the app at work — a conversation with an agent, two subagents running beside it, and the to-do list they share.
Local Operator runs AI agent assistants on your own machine, from a desktop chat app. You give an agent a goal; it plans the work, writes and runs Python on your device, reads and writes files, and asks before it takes anything risky. The whole run — messages, tool calls, commands, and results — stays in the conversation in front of you.
For the agent environment CLI and server backend, see the Local Operator repository.
Agent backend • Website • Examples
- Node.js 22.13.1 or newer, for the npm install paths below. nvm is a good way to manage Node versions. The desktop installers need no toolchain.
# Download and run in one command
npx local-operator-uiThis runs the latest version and launches the app.
# Install globally
npm install -g local-operator-ui
# Run the application
local-operator-uiPrebuilt apps are on the download page and the releases page:
- macOS: Download the
.dmg(or.zip) and open it. - Windows: Download the
.exeinstaller and follow the installation prompts. - Linux: Download the
.deb,.rpm, or.AppImagefor your distribution.
The Local Operator backend is bundled with the application and is installed automatically on first run. If you already have a Local Operator backend installed, the application detects it and uses it instead; by default it connects to the backend API at http://localhost:1111.
| Light | Dark |
|---|---|
![]() |
![]() |
chat — a working agent's tool rows, a blocked risky action, and the question it asked before continuing.
| Light | Dark |
|---|---|
![]() |
![]() |
subagents — two helpers working one request, each with its own elapsed time, context use and cost, and the next child queued behind the capacity gate.
| Light | Dark |
|---|---|
![]() |
![]() |
teams — agents grouped under a manager, with a roster, collaboration instructions and a project brief.
| Light | Dark |
|---|---|
![]() |
![]() |
media — a chart pasted in by hand and one the agent plotted, both rendered inline in the transcript.
| Light | Dark |
|---|---|
![]() |
![]() |
agent hub — community agents you can browse and download, by category.
| Light | Dark |
|---|---|
![]() |
![]() |
schedules — conversations that wake on a timer, with what ran and when they run next.
| Light | Dark |
|---|---|
![]() |
![]() |
projects — workstreams you and your agents track across sessions, as a board or a timeline.
| Light | Dark |
|---|---|
![]() |
![]() |
appearance — 59 colour themes ship with the app; Local Operator Dark is the default.
- Chat with agents — real-time conversation with markdown rendering for code blocks and formatted text, syntax highlighting, and per-conversation history.
- Agent management — create, update, and delete agents, and configure their settings: model and description (general), temperature and top_p (chat), and security prompt and execution permissions (security).
- Settings — system prompt configuration, API credentials management, and application configuration in one place.
- Local Operator API integration — the app talks to the Local Operator backend API and shows real-time status updates for long-running operations.
- Bundled backend — the Local Operator backend is installed automatically on first run on every platform; an existing backend installation is detected and used instead.
The codebase is organized for modularity and code reuse:
src/renderer/src/shared/: Contains all shared code, including components, hooks, stores, configuration, themes, and utilities. Use the@shared/path alias for imports.src/renderer/src/features/: Contains feature-specific code for the UI, organized by domain.src/renderer/src/app.tsx,main.tsx, etc.: Entry points for the Electron renderer process.build/,resources/,scripts/: Build assets, static resources, and build scripts.
Import conventions:
- Use
@shared/for shared modules (e.g.,import { useAgents } from "@shared/hooks/use-agents"). - Use
@features/for feature-specific modules. - The build also resolves the older aliases (
@renderer,@components,@hooks, etc.) for the files that still import them.
For more details on building or contributing, see the Contributing Guide and BUILD.md.
If you want to build the application from source, see the BUILD.md file for detailed instructions.
For macOS builds, the app bundles a standalone Python directly instead of requiring a Homebrew installation. This approach:
- Needs no admin privileges during installation
- Keeps the application self-contained
- Works offline
- Supports installing Python packages with pip
To set up the standalone Python for development:
# Run the setup script to download and configure standalone Python
pnpm setup-python-standaloneThis uses python-build-standalone, the same approach used by Datasette Desktop and PyOxidizer.
For more details, see the PYTHON_BUNDLING.md documentation.
All desktop applications are code signed and notarized to ensure security and trust:
- macOS: Applications are signed with an Apple Developer ID and notarized with Apple's notarization service
- Windows: Applications are signed with a trusted code signing certificate
- Linux: While code signing is less common on Linux, packages are built with integrity checks
For detailed information about the code signing and notarization process, see the CODE_SIGNING.md document.
Contributions are welcome! Please see our Contributing Guide for details on how to get started with development, code style guidelines, and our contribution process.
- The application will automatically install and start the Local Operator backend if it's not already running
- If you have an existing backend running on
http://localhost:1111, the application will use that instead - Check that the
VITE_LOCAL_OPERATOR_API_URLenvironment variable has not been set to a different URL. This value is set automatically tohttp://localhost:1111if a custom.envdoesn't specify otherwise - If you want to disable the automatic backend management, set the
VITE_DISABLE_BACKEND_MANAGERenvironment variable totrue - Verify network connectivity between the UI and the backend
- Check the application logs for error messages
- For macOS, the application uses a bundled Python framework instead of requiring Homebrew and pyenv
- If you encounter issues with the bundled Python, see the PYTHON_BUNDLING.md documentation
- As a fallback, you can try installing the backend manually with
pip install local-operatorand then start it withlocal-operator serve
- Check the console for error messages
- Ensure all dependencies are installed correctly
- Try clearing the node_modules folder and reinstalling dependencies
- Check for console errors in the developer tools
- Ensure you're using a compatible version of Node.js
- Try restarting the development server
Every time the app brings a window to the front it writes one line to its own backend log (~/Library/Application Support/Local Operator/logs/backend-service.log on macOS; the LOCAL_OPERATOR_LOG_DIR environment variable moves it):
[window-raise] trigger=second-instance mode=normal requested=focus pid=9182 cwd=/Users/you/project applied=restore+show+focus
trigger names what asked: initial-present (the app starting up), second-instance (a second launch sharing this profile), banner-click, viewer-focus or viewer-resume. pid and cwd, when they are there, name the process that asked — that is the one to stop if something keeps doing it. A run that raises nothing writes nothing, so an app that never came forward has no line at all — although a conversation that is WAITING for a window does: a headless launch against an app with no window open writes applied=parked, parked=<id> rather than a raise, and that conversation opens the next window you give the app. In the line above, mode is the window mode the raise ran under and applied is what it actually did.
A second launch only brings the window as far as IT asked: a headless run never raises it (it can still load the conversation it names), an inactive one orders the window without activating the app and without pulling it back out of the Dock, and a launch that declares nothing — you double-clicking the app while it is already running — still comes to the front.
If you encounter issues not covered here, please:
- Check the GitHub Issues for similar problems
- Open a new issue if your problem hasn't been reported
Some general style and interaction UX here is inspired by deepseek-harness (dsh) - including the conversation measure's draggable width controls, whose geometry, hover cue and persistence shape were read from
its ConversationWidthControls and adopted with this app's own bounds.
This project is licensed under the MIT License — see the LICENSE file for details. It is open source because AI tools should be accessible to everyone, and your contributions and feedback help make that real.















