Ari DESK
In development · not yet shipped

A personal agent,
attended on your Mac.

Aricode is a coding agent. Aridesk is the second mode: a personal-agent runtime that lives in the same app but works for you — browsing the web, triaging email, running shell tasks, drafting messages — every sensitive call gated through your phone.

§

Preview · in flight

Aridesk is actively being built. The runtime, cron, broker, tools, templates, skills, MCP bridge and phone chat land as of v0.6; the desktop dashboard ships in the current Aricode app under the Desk tab. The isolation model is a host process pinned to the agent's workspace/ directory plus a multi-tier approval broker; container-grade sandboxing is on the long-horizon roadmap, not the next folio.

The idea

Two agents, one runtime.

The aricode desktop already knows how to hold a conversation, stream a model, invoke tools, and pair with your phone over end-to-end encryption. Aridesk reuses all of that, but points the agent at a different kind of work.

Instead of a repo on your disk, each Aridesk agent gets its own persona, its own pinned workspace, its own browser profile with persistent cookies, and its own toolset. You create them the way you'd create folders: give them a name, drop in a soul.md, pick a template, start chatting.

Aricode — coding mode
Works on your code
Point it at a repo. It reads, edits, runs, and commits. Section-scoped, one session at a time, your files on disk.
Aridesk — personal mode
Works for you
Point it at a task. Many agents at once, each with its own pinned workspace, its own browser profile, its own memory. Sensitive calls stall for your approval on the phone before they fire.
Feature set

Everything an agent needs
— and a gate around it.

01 · Persona

File-based agent config

Every agent is a directory: soul.md persona, instructions.md task scope, agent.md YAML config, memory.md rolling context. Version-control them, sync between machines, diff persona changes like code.

soul.md instructions.md agent.md memory.md
02 · Multi-agent

Many personalities, one relay

Run a research agent, an inbox triager, a shopping assistant, and a calendar secretary at the same time. Each gets its own pinned workspace, model selection, browser profile, and memory. Switch between them as tabs on the phone.

independent state per-agent model
03 · Gate

Pin, policy, petition

Three tiers of gating before any tool call fires. Workspace pin — every shell, file, and browser call is rooted at the agent's workspace/; paths outside it are rejected outright. Exec policy — shell calls pre-classify into auto (safe reads), gate (asks once, can be remembered), or deny (foot-guns, never run). Approval petition — gated calls stall as a card on your phone with full preview, Approve / Deny / Always-allow scoped to the target.

workspace pin exec policy phone petition audit log
04 · Browser

A browser the agent owns

Chromium + Playwright driven over CDP on the host, with a per-agent browser-profile/ directory as its user-data-dir. Cookies, local storage, and session tabs survive restarts — the agent stays logged into the sites you gave it access to. The browser context spins up lazily on first navigate and closes after idle, so a sleeping agent costs nothing.

browser.navigate browser.click browser.extract browser.snapshot
05 · Shell

A terminal, pinned

A shell pinned to the agent's workspace/ directory. Ripgrep, curl, node, python, git inherited from the host. Timeouts per call, stdout/stderr streamed back as tool output. The exec policy classifies each command before it runs — safe reads (ls, git status) skip the prompt; mutating commands gate to your phone; foot-guns hard-deny.

terminal.run timeout
06 · Files

Workspace, not filesystem

Read, write, edit, and search files inside the agent's workspace/ directory. Paths are pinned — anything outside the workspace stalls for phone approval. Drop documents in from the host to give the agent material, export artifacts back when it's done.

file.read file.write file.edit file.search
07 · Web search

Actual knowledge of today

Brave Search API, wired on the host side and exposed as a single web.search tool. Configured per-agent or globally, so scoped keys are trivial.

brave search
08 · AppleScript broker

Mail, Calendar, iMessage — safely

A host-side broker exposes macOS automation to the agent. Every AppleScript call routes to the phone for approval, with an optional always-allow rule scoped to a specific target. Nothing runs unreviewed. The broker is in-process today — the runtime, the broker, and the relay are co-located in the Aricode app, so latency is zero and there's no socket to lock down.

Mail.app Calendar.app Messages Shortcuts Reminders
09 · Send-to-phone

The agent can ping you

A dedicated tool emits a desk.agent.notify frame up the relay. Long jobs can finish and tap you on the shoulder. Cron-style runs can report their summary unsolicited.

send-to-phone unsolicited messages
10 · Toolsets

Capability as configuration

Declare toolsets: [browser, terminal, files, web] in agent.md. Add fine-grained allow/deny lists for specific tool names. Deny always wins over allow — same semantics as OpenClaw.

allow / deny per-agent scopes
11 · Memory

A notebook the agent edits

Each agent gets a memory.md that it can rewrite through a memory.update tool, plus a recall database for incremental facts. Loaded whole into the system prompt; you can edit it by hand too. A nightly dreaming pass that consolidates transcripts back into the notebook is scheduled for v0.2.

agent-curated human-editable
12 · Phone UI

Messaging, not remote control

A dedicated Desk tab in AriCompanion lists agents as cards and opens each into a messaging-style chat. Tool calls render as inline cards, approvals as blocking prompts, images attach via the composer. No desk, no laptop needed.

DeskAgentsListScreen DeskAgentChatScreen DeskApprovalCard
13 · Approvals

Every sensitive call asks first

Before AppleScript runs or any gated tool fires, the broker emits a desk.approval.required frame. The chat surface stalls on a card with the full script preview, Approve / Deny buttons, and an always-allow for this target row that writes a scoped rule.

per-call review scoped rules audit log
14 · Transport

Same end-to-end crypto as AriCore

X25519 handshake, ChaCha20-Poly1305 on every frame, HKDF-SHA256 session keys, fingerprint verified on both ends. The relay sees ciphertext; agents on the same Mac register as peers on the same encrypted channel.

X25519 ChaCha20-Poly1305 HKDF-SHA256
15 · Lifecycle

Lazy and cheap

Agents load on first message, stay warm while conversations are live, and close their browser context after idle. No always-on daemon unless you want one. The runtime is co-hosted inside the Aricode desktop app — quit the app, the agents quit with it.

idle auto-stop warm re-attach
16 · Capabilities gate

No broken tabs on old installs

The desktop's hello frame declares capabilities.desk: true only when aricode desk init has run. The phone hides the Desk tab until it sees that flag, so pre-Aridesk installs look the same as before.

capabilities.desk feature-gated UI
17 · CLI surface

Everything from the terminal too

A full aricode desk subcommand group: init, new, list, edit, logs, start, stop, doctor. And a /desk <agent> slash in the aricode REPL for local prompts.

desk init / new / list desk doctor
18 · Model-agnostic

Whatever provider you want

Each agent's agent.md declares model: provider:name. Mix and match: one agent on ChatGPT, one on Copilot, one on local Ollama, one on Anthropic — running concurrently, each with its own keys.

OpenAI Anthropic Copilot OAuth ChatGPT OAuth Ollama
Architecture

Agent at the gate.
Broker on the outside.

The agent runs as a host process pinned to its own workspace/ and browser profile. The Mac's native integrations (AppleScript, Keychain, the phone channel) sit behind an approval broker: anything outside the pin stalls as a petition on the phone before it fires. Three tiers gate every call — the workspace pin, the exec-policy classifier, and the phone approval card — and every decision is appended to a JSONL audit log on disk.

┌─ iPhone ──────────────────────────────────────────────┐ AriCompanion · Desk tab ├ DeskAgentsListScreen ├ DeskAgentChatScreen └ DeskApprovalCard └──────────────────────┬────────────────────────────────┘ X25519 + ChaCha20-Poly1305 ┌─ Mac (host) ─────────▼────────────────────────────────┐ aricode desk runtime ├ relay server ◄──── encrypted frames ├ agent manager ├ cron scheduler └ approval broker (AppleScript, rules, ledger) petitions routed to phone ┌─ agent process, pinned per agent ─────────────┐ │ │ agent-loop ◄── streamModel (provider) │ │ ├ browser.* (Chromium + Playwright) │ │ ├ terminal.run (pinned to workspace/) │ │ ├ file.{read,write,edit,search} │ │ ├ web.search │ │ ├ applescript.run ── approval ─► phone │ │ └ memory.update │ │ │ dirs: workspace/ · browser-profile/ gate · workspace pin · exec policy · petition audit · approvals.jsonl · rules.json └────────────────────────────────────────────────┘ └───────────────────────────────────────────────────────┘
Toolsets

Bundles you mix,
names you allow or deny.

Toolsets are the primary unit of capability. Declare them in agent.md; narrow further with tools.deny. Deny always wins.

Toolset
What it grants
Tool names
browser
Full headless Chromium driven via CDP on the host, one context per agent. Cookies and local storage persist through a per-agent browser-profile/ directory used as Chromium's user-data-dir.
browser.navigate
browser.click
browser.fill
browser.extract
browser.screenshot
browser.snapshot
browser.wait_for
terminal
Shell pinned to the agent's workspace/ directory with a per-call timeout. The exec policy classifies each command as auto, gate, or deny before it runs, so safe reads skip the approval prompt and foot-guns never reach the shell.
terminal.run
files
Read, write, surgical edit, and search files in the agent's workspace/. Paths outside the pin stall for phone approval.
file.read
file.write
file.edit
file.search
web
Host-side web search via Brave Search API. Separate from the browser — useful when you just want a query result without driving a page.
web.search
host
macOS automation via the approval broker: send an email, add a calendar event, text someone, run a Shortcut, create a reminder.
applescript.run
send-to-phone
minimal
Just memory.update — for conversational personas that need nothing but context and reply.
memory.update
On disk

Plain files.
Grep-able, git-able.

No database, no binary blobs (except the browser profile, which you probably want to keep uncommitted). Every agent is a directory you can read with ls.

agents/
  research/
    soul.md              # persona / system prompt
    instructions.md      # task scope
    agent.md             # YAML: model, toolsets, image, limits
    memory.md            # rolling memory, agent-curated
    history.jsonl        # conversation transcript
    workspace/             # pinned cwd for shell + files
    browser-profile/       # used as Chromium user-data-dir
  inbox/
  calendar/
  shopper/

templates/               # seeded by `aricode desk init`
  research/
  inbox/
  calendar/
  shopper/

broker.sock            # host AppleScript broker (0600)
approvals.jsonl        # audit log of every approve/deny
rules.json             # "always allow" whitelist entries
Wire protocol

New frames,
same encrypted channel.

Aridesk extends the existing AriCompanion relay with a desk.* frame family. No new transport, no new crypto. The phone and desktop mirror these cases in TS and Swift.

desk.agent.listPhone pulls the agent roster from the paired desktop.
desk.agent.createCreate a new agent from a template on-device.
desk.session.openOpen a chat with an agent; returns the last N messages.
desk.messageUser message (text + optional base64 attachments) to the agent.
desk.deltaA streaming chunk of the agent's reply, back to the phone.
desk.tool.callRender a tool-call card on the phone as the agent invokes a tool.
desk.tool.resultCompletion marker for a tool call — ok plus a short summary.
desk.approval.requiredThe broker is blocking on a sensitive op and needs user decision.
desk.approval.decisionPhone returns approve / deny, with optional "always allow" rule.
desk.agent.notifyUnsolicited agent message — "I'm done, here's the summary".
Approval flow

Every sensitive call
stops at your phone.

  1. Agent calls a gated tool

    The agent emits, say, applescript.run with a script that texts your partner.

  2. Broker checks the whitelist

    The host broker compares the call to rules.json. Exact match on script kind + target? Run it. No match? Hold the call.

  3. Approval request fans out to the phone

    A desk.approval.required frame travels the relay. The chat surface stalls on a card that renders the script verbatim.

  4. You approve, deny, or whitelist

    Approve once, deny, or check always allow for this target to write a scoped rule that applies next time.

  5. Broker executes and audits

    The script runs via osascript on the host. The decision and call are appended to approvals.jsonl.

  6. Agent sees the result

    The tool returns either the script output or a denial error, and the agent continues its turn.

// Per-agent whitelist.  Deny always wins.
[
  {
    "kind": "imessage.send",
    "target": "+44…0001",
    "reason": "partner"
  },
  {
    "kind": "calendar.add_event",
    "target": "*@work.example"
  }
]
Templates

Four seed personas
to start from.

Each template is a valid-on-its-own directory you can copy into agents/ by hand. aricode desk new is sugar on top.

R
Research

Browser + web search + files. Opens tabs, extracts, summarises. Good for market scans, literature reviews, "what happened this week".

I
Inbox

Host + files + memory. Reads Mail.app via AppleScript, drafts replies, flags what needs your attention.

C
Calendar

Host + memory. Understands your week, adds events, texts people to reschedule, surfaces conflicts before you hit them.

S
Shopper

Browser + memory. Keeps logged into your accounts, compares prices, tracks orders, reminds you when things are about to renew.

Roadmap

What's in v0.1 —
and what comes after.

In · current preview

  • Multi-agent from day one, file-based config under ~/.aricode/desk/
  • Host-process runtime pinned to per-agent workspace/
  • Three-tier gate — workspace pin, exec-policy classifier, phone petition
  • Approval audit log to approvals.jsonl with timestamp + decision source
  • Chromium + Playwright with per-agent persistent profile
  • Terminal, files, web search, MCP bridge (stdio + SSE + streamable HTTP)
  • Cron scheduler (five-field POSIX, in-process 15 s tick, per-agent cron.jsonl)
  • AppleScript broker with phone approvals + scoped always-allow rules
  • Skills — agent-local or global, Markdown + YAML, callable like any tool
  • Send-to-phone proactive messages, full-text-searchable memory
  • Seeded templates (research, inbox, calendar, shopper, …)
  • Desktop Desk dashboard + phone Desk tab, chat + approval UI
  • Encrypted over the existing AriCompanion relay (X25519 + ChaCha20-Poly1305)
  • aricode desk CLI subcommand group for scripting

Later · post-preview

  • Dreaming — nightly consolidation of transcripts back into memory.md
  • Standing Orders & Heartbeats — conversational cadences alongside cron
  • Session delegation — one agent spawning a scoped sub-session
  • Skills registry — shareable capability bundles with versioning + install command
  • Approval rule builder UI with templates and impact analytics from the audit log
  • Per-agent resource limits — CPU, memory, and runtime budgets enforced from agent.md
  • Tool-call replay — re-run a recorded call with tweaked args, for debugging long workflows
  • APNs push so agents can reach you when the app is backgrounded
  • LaunchAgent bundle so the runtime boots with the Mac
  • Image / video / music generation tools · voice mode
  • Windows and Linux host support
  • Container-grade sandboxing — long-horizon, when the runtime stabilises and the threat model warrants it; not the next folio.

A personal agent you can actually trust,
because nothing sensitive happens
without a nod from your phone.

Follow the work on GitHub AriCore — the phone side →