Tech13 min read

Rebuilding "Kana": Orchestrating AI Agents Across Multiple PCs with Pi, Qwen, and Tailscale

IkesanContents

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 / ArchitectureDocumented ScopeAreas Requiring Further Verification
Meta MuseDedicated computer, terminal, and browser; handles persistent chat and background jobsHow to bridge existing local CLIs and project rules across multiple personal machines
OpenAI dotsConnects cloud environments and one personal PC at a time; supports local Work/Codex tasksCross-machine orchestration routing across Claude, Pi, and custom environments
Claude Cowork DispatchAssigns tasks from persistent chat to desktop; development runs via Claude CodeHandoffs 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 AIsConnecting 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 TypeCurrent HandlingScope Exposed to AI
API tokens and credential filesUsed strictly by backend servers and CLI authenticationValues are never inserted into prompts or chat context
Target names, IDs, and pathsUsed for target selection and matchingProject names and file paths are visible to Qwen
Chat transcripts and historical logsSaved to SQLite on HDD; relevant raw text is injected on demandRecent messages and search matches are sent to Qwen
File attachmentsStored locally for text extraction and visual inspectionExtracted text and image data are passed to the AI handling the task
Backlog & ChatWorkMessages and issues fetched directly from configured accountsFetched text needed for responses or implementation is sent to Qwen/CLI
GmailSearch results and message bodies rendered directly from dedicated storage to UIOnly count and status reach Qwen; email bodies remain hidden
GA4, Search Console, AdSenseAnalytics reports rendered in custom chat widgetsOnly query status reaches Qwen; analytics numbers are withheld
Voice recordings for summarizationAudio files stored locally; background jobs handle transcription and summaryAudio and transcripts are sent to ModelScope; Qwen verifies candidates during search
Local repository filesRead and edited directly by assigned CLIsIf 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 WorkflowValidated Capabilities
Japanese article draftCodex planning, Claude drafting, file saving, Codex source verification
English article translationFull translation via Antigravity (AGY) and Qwen reader review
Standalone HTML prototypeCodex planning, Claude implementation, review loop, zip export
Scoped repository workIssue analysis and sandboxed implementation in test repositories
Backlog task processingCodex parsing project rules, fetching issues, and running re-scans upon completion
Scheduled and recurring jobsMulti-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 TargetKey Requirements Across Multiple PCs
Target routingReaching designated PCs and directories without misdirecting commands
Agent availabilityVerifying requested CLIs/models without silent fallback on failure
Permission scopeEnforcing folder restrictions and allowed actions regardless of assignee
Data handoffClearly accounting for what data was transmitted to which agent
Continuity & cancelTracking actual session IDs and returning prompts or abort signals to chat
Failure recoveryDistinguishing 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.