Rebuilding "Kana": Orchestrating AI Agents Across Multiple PCs with Pi, Qwen, and Tailscale
Contents
I want to delegate tasks to AI tools across multiple computers from a single conversation window.
Depending on the project and task, I need to choose between Codex on one PC, Claude Code on another, or an agent runtime like Pi connected to local models. I also want to select permissions, assigned agents, and specific model settings myself, while having instructions, progress, questions, and artifacts returned to the same window. This is the setup I am building with “Kana,” my custom multi-agent gateway tying together a web interface, persistent memory, a task ledger, and execution layers.
Managing the execution environment, task order, handoffs, and status across multiple AIs is what I refer to here as orchestration. For example, having Codex plan a task, handing off implementation to Claude, and routing artifacts back for verification.
Rather than trying to build full distribution across several machines at once, I started by preparing the prerequisites on a single primary Mac: the chat interface, memory persistence, task reception, and state management, testing how tasks are handed off to agents running locally.
In the previous Kana Chat architecture, the focus was strictly on blog production.
Connecting blog authoring, image generation, and Backlog in this iteration serves to test how tasks enter the system and how results return in real-world workflows. From here, the goal is to expand outward to execution environments across different machines.
Deciding Which AI Runs on Which PC
For example, I want to say: “Fix the project on the dev PC using Codex,” or “Clean up these files using Pi on the secondary PC.”
However, the system is not yet at a point where remote tasks can be dispatched to other PCs seamlessly.
Each computer has different files, runtime environments, authenticated AI CLIs, and project-specific handling rules.
Beyond establishing a network connection to a PC, the gateway must execute the specified AI in the correct directory, route clarification prompts back to the chat, and determine when a task has actually concluded.
flowchart TD
U["Browser Chat Interface<br/>Kana"]
Q["Pi & Qwen<br/>Consultation & Instruction Formatting"]
G["Execution Layer on Mac<br/>Target Resolution, Queue & State"]
D["HDD Storage<br/>Memory & Task Ledger"]
M["Local CLI on This Mac<br/>Codex, Claude, Antigravity"]
A["Remote Codex & Claude<br/>Future Targets"]
B["Remote Pi & Local Models<br/>Future Targets"]
R["Results, Clarifications, Artifacts"]
U <--> Q
Q <--> G
G <--> D
G --> M
G -.-> A
G -.-> B
M --> R
A -.-> R
B -.-> R
R --> G
G --> U
classDef future stroke-dasharray: 5 5;
class A,B future;
Solid lines show the connections implemented locally on the Mac; dashed lines represent planned expansion to multiple machines.
Being able to open the browser interface from another PC is entirely different from being able to dispatch tasks to AI agents on that PC. Having the former working does not mean the latter is complete.
Decoupling Task Permissions from Assigned Agents
Beyond selecting a computer, I want to control which AI handles each task and what permissions are granted.
Some workflows require splitting roles across research, implementation, review, and publishing, while others can be handled end-to-end by a single agent. The chat-facing Qwen is separated from the background agents performing the work.
For instance, a research agent might receive read-only access, an implementation agent gets test execution and folder edit rights, and a publishing agent is granted deployment permissions for final artifacts.
Even in the current Mac-only pipeline, structured division already exists: Codex handles planning before handing off drafting to Claude.
Ultimately, the goal is to choose the target PC, agent, model, and allowed operations based on the project’s rules and the task at hand.
Model selection and permissions are tracked as separate attributes; changing the assigned agent does not automatically alter file editing or deployment rights.
Comparing with Muse, dots, and Cowork
Dispathing tasks from a chat, running work in the background, and receiving results is not unique to Kana; existing tools share similar patterns.
Here is how the connectivity documented for each product compares with what I need:
| Product / Architecture | Documented Scope | Areas Requiring Further Verification |
|---|---|---|
| Meta Muse | Dedicated computer, terminal, and browser; handles persistent chat and background jobs | How to bridge existing local CLIs and project rules across multiple personal machines |
| OpenAI dots | Connects cloud environments and one personal PC at a time; supports local Work/Codex tasks | Cross-machine orchestration routing across Claude, Pi, and custom environments |
| Claude Cowork Dispatch | Assigns tasks from persistent chat to desktop; development runs via Claude Code | Handoffs to custom heterogeneous environments, including Codex or Pi on remote PCs |
| This Project (Kana) | Mac interface, shared memory and task ledger, controlled dispatch to multiple local AIs | Connecting remote execution targets while preserving approval, cancel, and recovery hooks |
Cowork also offers cloud-based execution, but the table focuses specifically on Dispatch for local execution.
Based on available documentation, existing products do not yet provide a native way to bind disparate local CLIs across multiple heterogeneous PCs under unified rules.
Permission management on connected apps also exists in commercial products.
For example, dots inherits app permissions and separates reading email from sending it. Muse documents approval checkpoints before sending emails or completing purchases. In addition to approval gates, it is critical to track where data retrieved under those permissions is forwarded.
Tracking Real Execution Models and Reasoning Settings
When delegating tasks from dots to Codex locally, it was difficult to tell which exact model was actually running under the hood.
Knowing that Codex was invoked is not enough if you cannot verify whether your preferred model tier or reasoning effort was applied. In a custom setup, this visibility should be transparent.
To address this, Kana’s task ledger records the assigned agent name, configured model, reasoning effort values, and the actual model information extracted at runtime as separate fields.
Even in the current Mac setup, arguments passed to Codex (such as model and reasoning effort) are recorded alongside execution logs.
For Claude, the model name is captured from CLI startup events to distinguish between configured targets and runtime realities. If an event lacks model confirmation, the ledger does not assume it matched configuration.
This allows every job to be traced back to who ran it, what model was requested, and what actually executed.
Retaining this distinction will be essential when scaling across machines.
Overlap with OpenClaw and Project-Specific Requirements
OpenClaw already provides features like remote command execution nodes and agent configuration for models, workspaces, and tools.
These concepts closely match what Kana requires.
What I am focusing on in this implementation is how to map existing PCs, CLI instances, authentication tokens, and project-specific guidelines into a cohesive workflow.
Every job needs an explicit target and assignee, existing changes must be preserved, and actual results must flow back. Crucially, if a specified AI is unavailable, the system must never silently substitute another model without confirmation.
For now, I use Pi as the execution foundation for the chat gateway, expanding connections to fit my current setup step by step.
Long-Term Memory Inherited from the Voice Server
Saving conversations to external HDD storage did not originate with this gateway project.
It grew out of designing long-term memory for voice chat, where previous conversations could be recalled across sessions to revisit specific statements. Later, I ran integration tests with the voice server and clarification dialogues.
The current memory system builds directly on that work.
The requirement shifted from remembering voice chats to making conversations from the browser UI or other PCs accessible across model sessions.
When handing work to multiple AIs, the system must be able to retrieve past decisions and the exact original wording of user prompts.
Instead of relying solely on what a model retains in active context, this architecture preserves raw logs and provenance. The external drive acts as the centralized store for both transcripts and task states.
While the voice server relies on Qdrant for semantic vector search, standard chat in Kana currently uses SQLite for verbatim logging and substring search. The underlying memory problem is shared, but the retrieval engines and integration scopes remain separated.
Defining Information Boundaries for External AIs
When connecting multiple AIs, simple app-level authorization is not enough to define where data flows.
You must decide what information reaches the fetching scripts, Qwen in the chat, execution agents like Codex and Claude, and the human operator on screen.
Even if an API token is never passed to a model prompt, including fetched response bodies in a tool return value puts that content in front of the model.
Similarly, searching past conversations stored on a local HDD still transmits matching excerpts to Qwen when answering. Storing data locally is not the same as keeping inferences on-device.
Here is how boundaries are drawn in the current implementation:
| Data Type | Current Handling | Scope Exposed to AI |
|---|---|---|
| API tokens and credential files | Used strictly by backend servers and CLI authentication | Values are never inserted into prompts or chat context |
| Target names, IDs, and paths | Used for target selection and matching | Project names and file paths are visible to Qwen |
| Chat transcripts and historical logs | Saved to SQLite on HDD; relevant raw text is injected on demand | Recent messages and search matches are sent to Qwen |
| File attachments | Stored locally for text extraction and visual inspection | Extracted text and image data are passed to the AI handling the task |
| Backlog & ChatWork | Messages and issues fetched directly from configured accounts | Fetched text needed for responses or implementation is sent to Qwen/CLI |
| Gmail | Search results and message bodies rendered directly from dedicated storage to UI | Only count and status reach Qwen; email bodies remain hidden |
| GA4, Search Console, AdSense | Analytics reports rendered in custom chat widgets | Only query status reaches Qwen; analytics numbers are withheld |
| Voice recordings for summarization | Audio files stored locally; background jobs handle transcription and summary | Audio and transcripts are sent to ModelScope; Qwen verifies candidates during search |
| Local repository files | Read and edited directly by assigned CLIs | If an agent uses a cloud model, code read by that CLI is processed externally |
The Gmail and analytics rows reflect cases where raw content is intentionally withheld from the LLM.
If I manually paste an email into the chat, it becomes a standard prompt to Qwen. Allowing an app connection to display content in the UI does not grant blanket permission for LLM analysis.
Conversely, Backlog and ChatWork integration requires the AI to read message contents to answer questions, so text necessarily leaves the local machine.
Rather than applying a uniform filter, the system acknowledges that withholding text prevents detailed reasoning, while forwarding text demands conscious review of the destination.
Even if a CLI runs locally, using a cloud-backed model means inference occurs off-premises. Connecting local models via Pi is handled as a separate track; Kana as a whole cannot be described as fully local.
Core Infrastructure: Chat, Memory, and the Task Ledger
For the primary conversation interface, the current setup uses Qwen3.7-Plus via API paired with Pi.
Calling Pi’s RPC mode from a Python server provides scoped tools for memory retrieval, attachment handling, and task intake. Qwen is not granted arbitrary shell execution or direct edit access to repositories.
The web UI runs locally on this Mac and is accessible across devices using Tailscale Serve over a private network.
The interface maintains a continuous conversation thread across browser restarts. Task status, timestamps, and artifacts are monitored on a dedicated tab.
Transcripts and execution states are persisted to SQLite on external storage.
Normally, recent history is loaded directly, falling back to keyword search when older context is needed. Capture hooks across configured AI CLIs record origin, device, and session metadata, queuing payloads locally if the central server is unreachable.
The task ledger distinguishes between received, started, in-progress, awaiting-confirmation, completed, and failed states.
A friendly confirmation from the chatbot does not register as an active task; only a persistent task ID tied to the request serves as valid proof. Rather than scraping terminal text, status is tracked via structured events, session IDs, process exit codes, and generated artifacts.
When asked “What is the status?”, Qwen queries the ledger directly.
It avoids treating historical mentions of “in progress” in past messages as the current state. Jobs whose conclusion cannot be confirmed remain flagged as unknown, preventing duplicate writes or deployments upon server restarts.
Validating Agent Handoffs on a Single Mac
Before expanding to other PCs, I validated concrete workflows on my primary Mac.
Qwen handles initial consultation, formatting instructions before handing off work once requirements are met. The chat interface remains responsive for other conversations while background jobs run.
| Tested Workflow | Validated Capabilities |
|---|---|
| Japanese article draft | Codex planning, Claude drafting, file saving, Codex source verification |
| English article translation | Full translation via Antigravity (AGY) and Qwen reader review |
| Standalone HTML prototype | Codex planning, Claude implementation, review loop, zip export |
| Scoped repository work | Issue analysis and sandboxed implementation in test repositories |
| Backlog task processing | Codex parsing project rules, fetching issues, and running re-scans upon completion |
| Scheduled and recurring jobs | Multi-check completion, notification cancellation, and one-off agent execution |
In this architecture, Qwen does not execute every step directly; the Python execution layer manages process lifecycles and storage for each CLI.
For articles and coding tasks, planning, execution, and verification are decoupled. For Backlog processing, a repository-specific Codex instance handles everything from issue triage to completion checks according to local rules.
Read-only queries are kept strictly distinct from actionable tasks.
Asking “Are there new Backlog issues?” triggers a read-only check, while “Review and handle them” registers a task. Scheduled jobs retain their original prompt and parameters, preventing open-ended loops from running indefinitely without exit criteria.
Attachment analysis, image generation, and audio transcription are also tested as separate pipelines.
Generated images flow back into the originating conversation thread, while audio recordings retain raw clips alongside recognized timestamps.
Remaining Challenges for Multi-PC Orchestration
The next phase requires routing tasks to specific remote PCs and projects, invoking existing AI configurations, and returning results to the originating thread.
The goal is not to force all machines into a single unified credential or configuration, but to leverage existing local setups.
| Verification Target | Key Requirements Across Multiple PCs |
|---|---|
| Target routing | Reaching designated PCs and directories without misdirecting commands |
| Agent availability | Verifying requested CLIs/models without silent fallback on failure |
| Permission scope | Enforcing folder restrictions and allowed actions regardless of assignee |
| Data handoff | Clearly accounting for what data was transmitted to which agent |
| Continuity & cancel | Tracking actual session IDs and returning prompts or abort signals to chat |
| Failure recovery | Distinguishing completed, failed, and indeterminate states across disconnects |
Dispatching short tasks to remote PCs, handling mid-task clarifications, and reliably collecting artifacts will be the true test of expanding beyond a single machine.