Documentation

A complete guide to installing, configuring, operating, and extending aricode in real codebases. This page is intentionally detailed: it is meant to be the reference manual for the CLI, REPL, knowledge graph, dreaming system, and safety model.

aricode is a behavior-first coding agent for local or self-hosted models. It is designed to let the model read, edit, test, plan, and explore autonomously while keeping command execution and file mutation inside explicit guardrails.

Current desktop release: v0.5.2. Introduces Aricode Desktop (a native macOS app), session persistence across restarts, provider management, the Golden Thread visual rebrand, streaming transcript display, conversation search/export, inline diff viewer, integrated terminal, and knowledge graph visualization.

Companion release: AriCore v0.5.1. AriCore now syncs across your iPhone, iPad and Mac through your private iCloud. A new opt‑in Marketplace lets you share plugins, skills and personas with everyone else running AriCore. Personas gets its own bottom‑bar tab in Solo, sitting between Study and Browse. Memory is smarter: a new activity category decays over a week or two so transient context doesn't crowd durable traits, and a similarity check stops the model writing the same fact six ways. Dreams gain swipe‑to‑dismiss and check for duplicates before proposing new memories. See the AriCore section below.

Overview

aricode combines four things that most CLI coding agents keep separate: an interactive REPL, a persistent project memory, a codebase knowledge graph, and an autonomous exploration mode called dreaming. The result is a local-first agent that does not need to rediscover your project from scratch every time you open it.

The core operating model is simple:

Interactive REPL Knowledge Graph Project Memory Autonomous Dreaming Subagents Command Guardrails Behavioral Compilation Edit Intelligence

Requirements

Requirement Notes
Node.js 22+ The current CLI and Ink-based terminal UI target Node 22 or later.
npm Used for global installation, linking, and development builds.
OpenAI-compatible model backend Ollama works well by default, but any compatible endpoint can be used if it supports the required chat + tool-calling flow.
Local repo checkout aricode is built for real project directories, not isolated code snippets.

For the smoothest experience, use a terminal with standard ANSI support and a model that is genuinely capable of code editing, tool use, and longer reasoning loops.

Installation

The easiest path is the install script. It downloads the current public release tarball from install.aricode.dev/releases/, installs it globally, and verifies the command surface.

curl -fsSL https://install.aricode.dev | sh

If you want to inspect the exact public package being installed, you can fetch the versioned release tarball directly:

curl -O https://install.aricode.dev/releases/aricode-0.5.2.tgz
npm install -g ./aricode-0.5.2.tgz

For local development from a checkout:

npm install
npm run build
npm link

Verify the install:

aricode --version
aricode --help

aricode is the product name, npm package name, and global command. Existing workspaces under older .ariadne paths are migrated automatically. The public installer currently uses versioned tarballs on install.aricode.dev; a registry-based install flow can be layered on later without changing the CLI surface.

First Launch

Run aricode inside a project directory:

cd your-project
aricode

On the first launch in a workspace, aricode initializes session state and attempts to load a persisted knowledge graph for that project. If none exists, it offers to build one. The REPL then becomes your persistent operating surface for that workspace.

1. Start the REPL

Open the project directory and run aricode.

2. Build graph state

Accept the knowledge graph build if this is the first run.

3. Generate memory

Run /init to create .aricode/ARICODE.md.

4. Start working

Ask for a task directly, or use /plan if you want a reviewable plan first.

/init
/dream
/plan refactor the auth middleware to support JWT
fix the null pointer in src/parser.js

Operating Modes

aricode can be used in three primary ways:

Mode When to use it Example
Interactive REPL Ongoing multi-turn work, planning, debugging, patch review, dreaming, and graph-aware exploration. aricode
One-shot instruction Single task from a shell pipeline or quick scripted usage. aricode "explain the authentication flow"
Explicit one-shot pipeline Direct non-REPL execution via slash-style task routing. aricode one "add error handling to fetchUser"

The interactive REPL is the most capable mode. It is where planning, dreaming, transcript history, patch review, and session continuity all come together.

Configuration

aricode keeps a mix of global and per-project state. Global provider information lives outside the project, while project artifacts live under .aricode/. Existing legacy state is migrated automatically on first run.

~/.aricode/providers.json
Provider definitions, base URLs, active provider state, and related backend configuration.
~/.aricode/{workspaceHash}/
Persistent session state keyed by workspace path. Stores transcript history, summaries, and session configuration.
.aricode/
Project-local artifacts such as the knowledge graph, dream outputs, plans, memory, and hooks.

You can change the active model, backend, profile, context size, and context includes from inside the REPL at any time.

/model qwen2.5-coder:32b
/backend http://localhost:11434/api
/profile compact
/ctxsize 128000
/include src
/include test
/files

Providers & Models

aricode is backend-agnostic as long as the endpoint behaves like the OpenAI chat completions API and the selected model can reliably handle coding tasks and tool calling. In practice that means local Ollama, llama.cpp-based stacks, vLLM deployments, LM Studio, and other compatible systems all fit.

Ollama

ollama pull qwen2.5-coder:32b
aricode --base-url http://localhost:11434/api --model qwen2.5-coder:32b

You can also configure this interactively:

/backend http://localhost:11434/api
/model qwen2.5-coder:32b

Other OpenAI-compatible endpoints

/backend https://your-endpoint.example/v1
/model your-model-name
/provider list
/provider add

Model quality matters more than raw context size. aricode can manage context and structure, but it still depends on the backend model being competent at code reasoning, tool choice, and following long-running workflows.

Project Layout

After initialization and use, you should expect aricode to maintain the following project-local structure:

.aricode/
  ARICODE.md
  graph/
  dream/
  plans/
  hooks.json

And the following global structure per workspace:

~/.aricode/
  providers.json
  {workspaceHash}/
    session.json
    transcript.jsonl
    summary.md

The exact contents grow over time as the agent works, dreams, plans, and accumulates project memory.

REPL Workflow

The REPL supports both direct natural-language tasks and slash commands. A typical work session looks like this:

  1. Open the project and let aricode load or build the graph.
  2. Run /init if you want a fresh project memory file.
  3. Ask for direct work, or use /plan to separate planning from execution.
  4. Review pending patches with /diff and apply with /apply.
  5. Use /history, /status, /graph, and /dream as persistent support tools.
/status
/graph stats
/plan add structured logging to the worker queue
/execute
/diff
/apply

Command Reference

The REPL exposes a fairly broad slash-command surface. The list below reflects the currently shipped command registry.

Session & UI

Command Purpose
/helpShow available commands.
/statusShow session status and current state.
/view [ambient|focus|verbose]Set transcript detail level.
/focusToggle focus view.
/verboseToggle verbose view.
/historyShow recent transcript history.
/newStart a fresh conversation in the current workspace.
/resetReset workspace state.
/exitExit the REPL.
/copy [all]Copy the last response or the full transcript to the clipboard.

Models, Providers & Context

Command Purpose
/model <name>Switch the active model.
/backend <url>Switch the active backend URL.
/provider [add|list|name]Manage provider definitions.
/profile <name>Set the working profile, such as compact or balanced.
/context [text|clear]Set or clear persistent context.
/ctxsize <tokens>Set context window size.
/include <path>Add a file or directory to context includes.
/drop <path>Remove an include path.
/filesList currently included paths.

Task Execution

Command Purpose
/one <task>Run the one-shot pipeline.
/run <task>Run the main agent loop on a task.
/plan <task>Explore the codebase and create a plan.
/sectmode [on|off|status|init]Toggle section mode, check status, or initialize a section manifest. When active, tasks are distributed across code sections by a master planner. Use /sectmode apply-proposal to accept and /sectmode reject-proposal to decline a structural change proposed by the master.
/executeExecute the last approved plan.
/diffPreview the pending patch.
/applyApply the pending patch.
/write <path>Write the last code output to a file.
/spawn <task>Run a background task.

Codebase & System Inspection

Command Purpose
/read <path>Read a workspace file.
/search <pattern>Search workspace files.
/test <cmd>Run tests.
/shell <cmd>Run a shell command directly.
/git [subcommand]Run git commands.
/symbols [file]List indexed symbols.
/callers <name>Find call sites.
/wm <query>Query the world model.
/graph [on|off|query|explain|stats]Inspect or control the knowledge graph.
/store [conflicts|query <type>]Inspect the state store.

Memory, Setup & Dreaming

Command Purpose
/setupRe-run the setup wizard.
/initGenerate project memory in .aricode/ARICODE.md.
/memoryShow stored memories.
/forget <key>Remove a memory.
/dream [browse|summary|explore]Run or inspect autonomous codebase exploration. Use --depth shallow|deep|intensive to control exploration depth and --focus <area> to target a specific part of the codebase. browse opens the dream artifact browser, summary shows the journal, explore shows the futures tree.
/privileged [on|off]Toggle privileged command mode.

Knowledge Graph

The knowledge graph is aricode’s persistent structural memory of the codebase. It is not just a file index. It tracks symbols, imports, ownership relationships, runtime-adjacent structure, provenance, and higher-value relationships such as mirrors or connected modules.

Tracked entities

Files, functions, classes, methods, constants, and higher-order project concepts.

Relationships

Imports, calls, ownership, inheritance, type references, mirrors, and semantic links.

Provenance

Last commit, author, date, and related metadata for indexed files where available.

Live updates

Reads, writes, and edits feed back into the graph during active sessions.

The graph supports status views, codebase queries, context generation, and dream targeting. It is one of the main reasons aricode gets better on later sessions instead of remaining stateless.

/graph
/graph stats
/graph query auth middleware
/graph explain parser tokenizer

Project Memory

aricode maintains a persistent project memory file at .aricode/ARICODE.md. Older memory files are migrated automatically. It is intended to capture durable architectural context, conventions, terminology, and known constraints that should inform every later turn.

The memory file is generated by /init and enriched from several sources:

If you want aricode to internalize a non-obvious project rule, ARICODE.md is the canonical place to put it.

Autonomous Dreaming

Dreaming is aricode’s autonomous exploration mode. Instead of waiting for a task, aricode walks the codebase with a phased strategy and produces durable artifacts for later use. Dreaming is useful when a codebase is large, under-documented, or evolving quickly.

Dream phases

/dream
/dream --depth shallow
/dream summary
/dream browse
/dream explore

Artifacts are written under .aricode/dream/ and can later feed planning, memory generation, and graph-guided retrieval.

Dream tool restrictions

During dreaming, the model operates in a read-only sandbox. It cannot edit files, run shell commands, submit plans, or ask the user questions. The only exception is the synthesis phase, which is allowed to write files — but only to the .aricode/dream/ directory. This prevents the agent from accidentally modifying your codebase while exploring it.

Dream depth

DepthTurn budgetBest for
shallow~30 turnsQuick survey of a new codebase. Identifies structure and high-level patterns.
deep (default)~80 turnsFull exploration. Investigates threads, resolves questions, maps futures.
intensive~150+ turnsDeep investigation with no thread cap. Each thread gets generous budget. Use for thorough analysis of complex codebases.

Dream context

When dream context is enabled (/dream context on or via the settings toggle), aricode automatically injects relevant findings from past dreams into your task prompts. This gives the model background knowledge about your codebase without you having to explain it. Dream context is injected as a read-only preamble — the model can use it if relevant, but isn't forced to.

Dream artifacts

FileContents
dream_journal.mdNarrative summary of what was explored and found.
findings.jsonStructured findings with confidence scores.
futures_tree.mdPredicted future directions, risks, and refactor opportunities.
dream_state.jsonInternal state for incremental dreaming (threads, budget tracking).
codebase_map.mdHigh-level map of the codebase structure.
conventions.jsonDetected coding conventions and patterns.

Interrupting a dream

You can stop a dream at any time with Ctrl+C (CLI) or the Stop button (desktop). Partial results are saved after every phase, so an interrupted dream still produces useful artifacts. The abort signal propagates through all phase runners and the underlying agent loop.

Planning & Execution

aricode separates planning from execution when you want it to. Planning mode is ideal for larger refactors, multi-step migrations, and work that should be reviewed before code is touched.

/plan migrate the worker queue to structured events
/execute

Typical flow:

  1. Run /plan <task>.
  2. Review the generated plan and any clarifying questions.
  3. Approve or revise the plan.
  4. Run /execute when ready.
  5. Inspect pending changes with /diff and apply with /apply.

For smaller tasks, you can skip planning and ask directly in natural language or via /run.

Section mode

For larger apps with clear ownership boundaries, section mode lets a master planner split a task into narrower briefs for section-scoped agents. The master sees the broad conversation context; section agents stay constrained to the files defined in the section manifest.

Setting up section mode

/sectmode init    # Generate a section manifest from your project structure
/sectmode on      # Enable section mode for subsequent tasks
/sectmode status  # Check current section mode state
/sectmode off     # Disable section mode

The manifest lives at .aricode/sections/manifest.json and defines which files belong to which section. Each section has an id, label, description, and file list. The master planner reads this to decide how to distribute work.

How execution works

  1. You submit a task via /run or natural language.
  2. The master planner analyzes the task and decides which sections need changes.
  3. If the master thinks the section structure should change, it proposes a resector. You can accept with /sectmode apply-proposal or reject with /sectmode reject-proposal.
  4. Otherwise, it dispatches work to section agents — each one operates within its file scope.
  5. A verifier agent checks cross-section consistency after all section agents finish.
  6. The master writes a final summary.

Section ID resolution

Section IDs can be matched by exact ID, normalized ID (lowercased, stripped), or slugified label. For example, a section labeled "User Interface Components" can be dispatched to as user-interface-components, user_interface_components, or the canonical ID from the manifest.

Subagents

For broader or parallelizable work, aricode can spawn subagents. These are bounded agents with inherited context and constrained capabilities. They are useful for large codebase exploration or breaking down a complex problem without flooding the main context with raw intermediate work.

Type Purpose
GeneralFull-capability worker for broad subtasks.
ExploreRead-only research and codebase mapping.
PlanStrategy generation without direct code mutation.

Subagents inherit the main session’s safety model and are subject to concurrency and budget limits so they remain support workers, not uncontrolled autonomous branches.

Tool Surface

The model-facing tool surface is what turns aricode from a chat shell into a coding agent. The exact implementation evolves, but the current core toolset centers on file access, editing, shell execution, graph queries, scratchpad state, planning, and lifecycle control.

Tool Purpose
read_fileRead a file, optionally within line ranges.
list_filesFind files without reading their contents.
searchSearch text across the workspace.
edit_fileApply targeted search/replace edits.
write_fileCreate or overwrite files.
run_commandRun an allowlisted shell command.
fetch_urlFetch a URL as text.
query_codebaseQuery indexed symbols and graph state.
analyzeRun deeper structural analysis.
scratchpadPersist structured notes within the session.
spawn_agentLaunch a bounded subagent.
submit_planSubmit a plan from planning mode.
request_more_stepsAsk for additional reasoning budget.
ask_userRequest human input when needed.
finishComplete the current task.

Command Safety

aricode uses a default-deny command policy. The model cannot simply run arbitrary shell code. Commands are classified into tiers, validated, and either allowed, blocked, or escalated into an approval flow.

Tier Typical behavior Examples
Read-only Generally auto-approved. ls, cat, grep, find, git status
Mutating Requires normal approval or policy allowance. npm run build, eslint --fix, git commit
Privileged Requires explicit privileged enablement. npm install, networked installs, broader system modification

Environment variables are sanitized before agent-executed commands. Sensitive keys and tokens are stripped from the command environment unless you deliberately opt into a broader mode.

/privileged on
/privileged off

Context Management

aricode actively manages the conversation context to stay within the model's context window. This happens automatically — you don't need to configure it unless you want to.

How compaction works

When the conversation history approaches the context window limit (set by /ctxsize or --max-context-tokens), aricode runs a multi-stage compaction:

  1. Micro-compaction — removes old tool results that are no longer relevant (e.g., file reads from 20 turns ago).
  2. Knowledge extraction — pulls durable facts from the conversation into the knowledge graph before dropping them.
  3. Summarization — condenses older conversation turns into a compact summary that preserves key decisions and context.
  4. Rehydration — rebuilds the context window with the summary, recent turns, and active tool state.

Compaction is visible in the REPL as a status message. In the desktop app, the spinner mode changes to "requesting" during compaction.

Persistent context

You can inject fixed text into every prompt using /context. This is useful for project-specific instructions that should always be present:

/context This project uses SQLAlchemy 2.0 async style. Always use async session.
/context clear

Include paths

Files added with /include are read and injected into the system prompt on every turn. Use sparingly — each included file consumes context window budget.

/include src/core/types.ts
/include docs/architecture.md
/files    # List current includes
/drop src/core/types.ts

World Model

The world model is aricode's in-memory representation of your codebase structure. It's built from AST parsing and updated live as the agent reads and edits files. The knowledge graph builds on top of it.

What it tracks

Querying

/symbols              # List all indexed symbols
/symbols src/app.ts   # Symbols in a specific file
/callers handleSubmit # Find all call sites for a function
/wm summary           # High-level world model summary
/wm deps src/app.ts   # Dependencies of a file

The world model is also available to the agent during execution — it uses it to understand code structure before making edits, and to assess the blast radius of changes.

Behavioral Compilation

When aricode reads structured test failures or runtime evidence, it can extract behavioral witnesses and compile them into a repair-focused behavior patch. This helps the agent distinguish between incidental code changes and actual contract-level corrections.

BEHAVIOR PATCH
Iteration 2: 8 -> 3 witnesses

REPAIR: normalizePhone (src/phone.js:5)
  equality: "(415) 555-0100" -> "+14155550100"

This system is especially useful when several failing tests reduce to one root-cause function or contract mismatch.

Edit Intelligence

aricode does not treat file mutation as the end of the story. After edits, it can run a secondary layer of analysis that checks whether the change is plausible in the context of the project.

Hooks System

Hooks let you attach your own automation to aricode lifecycle events. They are configured in .aricode/hooks.json and can be used to run formatters, local checks, setup scripts, or custom telemetry.

{
  "hooks": {
    "post-edit": ["npm run lint --fix ${file}"],
    "post-write": ["prettier --write ${file}"],
    "pre-command": ["echo 'Running: ${command}'"],
    "post-command": ["echo 'Finished: ${command}'"],
    "session-start": ["echo 'Session started'"],
    "session-end": ["echo 'Session ended'"]
  }
}

Hook output is incorporated back into the working session so the model can react to it.

Desktop App

Aricode Desktop is a native macOS application that provides a graphical interface for the aricode agent. It uses the same SDK and agent loop as the CLI — your providers, sessions, and project memory are shared between both.

Download: Aricode-0.1.0-arm64.dmg (macOS, Apple Silicon, ~97 MB)

Installation

Download the .dmg file, open it, and drag Aricode to your Applications folder. No other dependencies required — the aricode SDK, ripgrep, and all tools are bundled inside the app.

On first launch, the onboarding wizard will walk you through connecting to a model backend. You can choose from presets (Ollama, LM Studio, OpenAI, OpenRouter) or enter a custom URL. Your provider configuration is saved to ~/.aricode/providers.json and shared with the CLI.

Aricode Desktop — main three-panel layout with file tree, conversation, and detail panel.
The default three-panel layout in the shipped Vellum theme.

Layout & Panels

The app uses a three-panel layout wrapped by a custom title bar (with a workspace switcher on the left and a gear icon on the far right that opens Settings) and a status bar along the bottom:

PanelContentToggle
Title barWorkspace picker with recent-workspaces dropdown; settings gear on the top-rightAlways visible
Left — SidebarFile tree with git diff badges (Files tab) and per-workspace session history (Sessions tab)⌘\ or status bar button
Center — ConversationStreaming transcript, pinned messages rail, snippet bar, input composer, conversation minimap on the right edgeAlways visible
Right — DetailTabs for Activity, Context, Git, Schedule. Footer shows today's usage and links to the full dashboard.⌘⇧\ or status bar button
Status barAgent status dot + current phase, view toggles, token counters, shortcut chips (⌘⇧P, ?), version glyphAlways visible

Additional overlays can be toggled from the status bar or keyboard:

Conversation minimap

Once a conversation has more than three messages, a slim vertical rail appears on the right edge of the transcript. Each message is a tick coloured by role (amber for user, chalk for assistant, muted for system). Hover to reveal a viewport indicator that mirrors your scroll position, and click any tick to jump to that message. The rail fades to 35% opacity when you're not hovering over the conversation.

Pinned messages

Hover any assistant message to reveal a pin button on the top-right of its header. Click to pin; pinned messages get an amber thread marker in their left margin and surface in a "PINNED" rail above the transcript. Click any chip to jump back to that message. Click the × on a chip to unpin.

System row for slash commands

When you run a slash command that doesn't reach the model — /help, /status, /diff, and so on — a compact one-line system row appears in the conversation confirming what happened (e.g. ◇ /help · Opened command reference). Only task-style commands (/run, /plan, /execute, /one) are forwarded to the agent.

Command Palette

Press ⌘⇧P anywhere in the app to open the command palette — a fuzzy-searchable launcher for every action, slash command, and navigation target. It groups results by category (Go To, Commands, Workspace) and shows the keyboard shortcut for each entry so you learn them over time. / navigates, runs, Esc closes.

Keyboard cheatsheet

Press ? with the input unfocused to summon the keyboard cheatsheet — a four-column grid of every shortcut, grouped by General, Workspace, View, and Agent. The status bar also exposes shortcut chips (⌘⇧P Palette and ? Shortcuts) for discoverability.

Sign in with ChatGPT

If you have a ChatGPT Plus/Pro subscription, aricode can authenticate directly against your ChatGPT account instead of asking for an API key. Your conversations are billed against your subscription's quota, not against pay-per-token API credits.

The flow is standard OAuth 2.0 with PKCE, using OpenAI's public Codex CLI client — the same credential Apple's own Codex and the OpenCode plugins use.

How it works

  1. Click Sign in with ChatGPT in the onboarding wizard, or open Settings (⌘,) → Providers and click the gold Sign-in card.
  2. Aricode spins up a temporary loopback HTTP server on http://localhost:<random-port> and opens your default browser to auth.openai.com/oauth/authorize.
  3. Log in with your ChatGPT account in the browser. Approve the requested scopes.
  4. OpenAI redirects back to the local loopback URL with an authorization code. Aricode exchanges it for an access token + refresh token, writes them to ~/.aricode/auth.json at mode 0600, and closes the local server.
  5. The ChatGPT provider is added to your Providers list and made active. Start chatting.

Scopes requested

ScopeWhy
openidStandard identity scope
profileYour display name for the active-session label
emailShown in Settings to confirm which account you're signed in as
offline_accessIssues a refresh token so you stay signed in across restarts
api.connectors.readRead access needed for the ChatGPT backend API
api.connectors.invokeSends your prompts + tool calls through your subscription

Models available

Which models you can actually use depends on your ChatGPT plan, not on aricode. Plus accounts typically get GPT-5 and GPT-5 Codex; Pro plans get higher context windows and priority routing. If a model isn't in your plan, the request fails with a 403 and you can pick a different one in Settings → Model.

How aricode talks to ChatGPT

ChatGPT-OAuth tokens aren't accepted on the standard api.openai.com/v1 API. They authenticate against chatgpt.com/backend-api, which uses the Responses API (not Chat Completions). Aricode ships a small adapter (desktop/main/chatgpt-responses.ts) that translates the agent's tool-using chat turns into Responses API calls and streams the results back in the format the SDK expects. All of this is transparent — you just pick the provider and chat.

Token lifecycle

Signing out

Open Settings → Providers → click Sign out on the ChatGPT row. This removes the ChatGPT provider entry from providers.json and deletes ~/.aricode/auth.json. Your other API-key providers stay configured; the previously active one (or the first available) becomes the active provider again.

Security notes

Settings

The settings modal is opened from the gear button in the top-right of the title bar (or via ⌘,). It's a right-side slide-in drawer with a left navigation rail and six sections:

SectionContents
ProvidersAdd, switch between, and delete OpenAI-compatible backends. Data is stored in ~/.aricode/providers.json and shared with the CLI.
ConnectionOverride the active backend URL or API key for the current session. Inline editor with password-masked key display.
ModelPick the active model from the list the backend exposes.
TuningPer-model context window size, max response tokens, and sampling temperature. Settings are saved per-model and auto-restore when you switch back.
AgentProfile (compact / balanced), privileged mode, section mode, dream context augmentation.
AppearanceTheme picker with live preview swatches.

Model Tuning

Each model you use can have its own tuning parameters, persisted to ~/.aricode/model-settings.json and applied to every run:

Themes

Five hand-tuned themes ship with the app. The shipped default is Vellum — a warm, sepia-on-parchment light theme inspired by illuminated manuscripts. Each theme retools the entire chrome and the integrated terminal's ANSI palette.

ThemeMoodPalette
Vellum (default)Illuminated manuscriptSepia ink on warm cream, gold leaf accents. The only light theme.
Golden ThreadAriadne's flameAmber on deep warm black. The original brand palette.
Crimson ThreadThe labyrinth at duskRuby on ink-black. Wine-stained, romantic.
Midnight VerdantA library at 3 a.m.Sage on oak-dark green with copper at the edges.
QuicksilverBlueprint minimalismPlatinum on graphite. Monochrome. No glow.

Switching themes updates the app instantly — including the xterm.js terminal, which has its own palette tuned to each theme. The selected theme is stored in localStorage under aricode.theme.v1.

Context Inspector

The Context tab in the detail panel shows a live view of everything the agent has loaded for the current session:

The panel refreshes after every turn. The reload glyph in the top-right spins 180° on hover.

Usage & Cost

A compact Usage strip is permanently pinned to the bottom of the detail panel. It shows today's total tokens and — if you've configured per-model rates — estimated cost. The strip has a meander separator at the top and a 2-pixel amber bar scaled against a 100K-token reference.

Click the strip to open the full Usage dashboard as a modal:

Raw usage events are appended to ~/.aricode/usage.jsonl — one line per turn with timestamp, model, backend, workspace, and token counts.

Scheduler

The Schedule tab in the detail panel lets you configure aricode to run prompts automatically. Useful for overnight refactors, morning PR reviews, or any recurring task.

Four schedule kinds are supported:

Each entry captures a name, the target workspace path, the prompt text, and an enabled toggle. When the scheduled moment arrives, the main process fires an IPC event to the renderer, which submits the prompt through the normal agent loop. If the target workspace isn't currently active, a native notification nudges you to switch over rather than firing into the wrong session.

The scheduler uses per-occurrence dedupe keys (e.g. 2026-04-16 for daily, 2026-W16 for weekly) so each scheduled instance fires exactly once regardless of how often the tick loop runs. Schedules persist to ~/.aricode/schedules.json and survive relaunches.

Global Quick Prompt

Press ⌘⌃A from anywhere in macOS — any app, any space — and a frameless Raycast-style mini-window appears in the middle of your screen. Type a prompt, press , and the response streams inline in the same window. Esc hides it. Clicking outside auto-hides, and the window dismisses itself 8 seconds after the response completes.

We deliberately avoided ⌘⌥Space (Spotlight / Finder uses it) and ⌘Space (Spotlight by default). ⌘⌃A is uncommon enough to land reliably across macOS configurations.

The quick prompt always submits to your currently-active workspace session. Use it for quick questions without leaving your editor.

Menu Bar Tray

A persistent menu bar icon () stays resident while the app is running. The icon's color reflects agent state: solid amber when idle, pulsing when the agent is thinking, ember-red on error.

Clicking the tray icon opens a menu with:

Snippets & Image Paste

Snippet bar

Above the input composer, a horizontal bar holds your saved prompts as click-to-send chips. The app ships five starters (Explain, Add tests, Write docs, Refactor, Review) and you can add, edit, or delete your own. Click any chip to submit its prompt; click the small on a chip (or right-click) to edit. Snippets persist in localStorage under aricode.snippets.v1. Collapse the bar with the ◇ SNIPPETS label; re-open with ◈ Snippets.

Image paste

With the input focused, ⌘V a screenshot or any clipboard image and a thumbnail appears above the composer with the filename and dimensions. Send the message and the image is embedded as a markdown data URL — multimodal-capable providers will see it. Remove the attachment with the × on the thumbnail before sending.

All Features

Everything the CLI can do, the desktop app can do — plus desktop-specific capabilities:

Keyboard Shortcuts

ShortcutAction
General
⌘KFocus input
⌘⇧PCommand palette
⌘FSearch conversation
?Keyboard cheatsheet
EscDismiss dialog / exit focus mode
Workspace
⌘NNew session
⌘OOpen workspace
⌘,Settings
⌘⇧EExport conversation
⌘QQuit
View
⌘\Toggle sidebar
⌘⇧\Toggle detail panel
⌘`Toggle terminal
⌘GToggle knowledge graph
⌘⌃FFocus mode (hide all chrome)
Agent
⌘⌃AGlobal quick prompt (works from any app)
Send message
⇧↵Newline in input
⌘VPaste image as attachment (in input)
/Open slash command menu

AriCore — Companion App for iPhone

AriCore is the iOS companion to aricode. It started as a phone-side surface for the desktop's coding agent and grew into a full personal assistant. As of v0.5.1 it has three modes, syncs across your devices through your private iCloud, and includes an opt-in community Marketplace:

All three modes share the same cryptographic pairing: the phone generates an X25519 keypair, a QR-code handshake establishes the session, and every frame is encrypted end-to-end with ChaCha20-Poly1305. The relay server sees only ciphertext and routing metadata. The app has no account, no analytics, and no crash-reporting that phones home — personal state lives on-device in SwiftData / the Keychain, with optional fan-out across your own devices via private CloudKit (see iCloud Sync below).

Install & First Launch

Install AriCore from the App Store. The app is free, requires iOS 17, and has no accounts or analytics. First launch lands you in Solo mode — the bottom tab bar shows Threads · Study · Personas · Browse · Models · Providers · Settings. (Linked and Desk appear automatically when a paired desktop is detected.)

iCloud Sync

AriCore uses CloudKit private database sync so your conversations, memories, personas, notes, ONE canvases and study courses travel between your iPhone, iPad and Mac. There's nothing to configure — if you're signed into iCloud and have iCloud enabled for AriCore in iOS Settings, it just works. First launch on a new device briefly holds the UI while CloudKit imports your data.

Sync runs through your personal iCloud. Apple operates the infrastructure; data is encrypted in transit and at rest in your iCloud account. We have no access to it — CloudKit explicitly prevents developers from reading users' private records, and AriCore has no server-side component that could.

If you're signed out of iCloud, AriCore falls back to local-only operation and the app still works fully on-device. Sign in later and sync resumes automatically; no data is lost in either direction.

Marketplace

The Marketplace is AriCore's opt-in community gallery for sharing plugins (ONE-mode JavaScript extensions), skills (small tools Ari can call), and personas (full assistant configurations including system prompt, default model and tool allowlist). It's backed by the same CloudKit container's public database — visible to everyone running AriCore, distinct from your private sync.

You don't have to use it. Nothing is published unless you explicitly hit Publish on an item you own. Before your first publication you pick a public handle; that handle plus an opaque per-account identifier (derived from your iCloud user record — your email is never visible) are attached to each item, comment, rating and flag you create.

Every install shows you the source first. Plugins display their full JavaScript before they touch ONE; skills display their tool definition and permission scope before they're enabled; personas display their system prompt and tool allowlist before they're added. Nothing runs without your tap.

Moderation is light-touch: anyone can flag anything, and items with multiple flags are hidden pending review. The default Ari persona is locked out of publishing so it can't be shadowed by a similarly-named copy.

Items you've published are editable and deletable from inside the app at any time. Deleting an item removes it from the public database, though copies anyone has already installed remain on their devices.

The empty state in Threads nudges you toward the two ways to make Solo useful: add a provider (cloud BYO-key) or import a local .gguf model. You can do both, and switch model on a per-thread basis from the chat header.

Strong recommendation: use an API provider. Local on-device GGUF inference is a real fallback for privacy-sensitive moments and offline use, but for day-to-day Ari you want a frontier-class model with full tool support, fast streaming, and a context window that can fit a real browse session. Pick a provider before anything else.

  • OpenAI — the easiest start. gpt-5.4-mini as Ari's default for ordinary chat, browsing, briefings — cheap, fast, full tool support. gpt-5.5 for the harder turns; gpt-5.4-nano for high-volume cheap routing. Pay-as-you-go, top up $5 once and you'll have weeks of casual use. Tool support is rock-solid.
  • Ollama Cloud — best value if you use Ari every day. Billed on GPU time, not per-token — Pro tier is $20/month, Max is $100/month. Daily-driver picks: deepseek-v4-flash, qwen3-next, gemma4, nemotron-3-nano, ministral-3. Frontier-class picks for harder turns: deepseek-v4-pro, kimi-k2.6, minimax-m2.7, glm-5.1. Add as an OpenAI-compatible provider with base URL https://ollama.com; check Ollama's docs for the latest model list.

Both provide tool calls + streaming, and both let you keep your key in the Keychain — nothing is shared with us.

Solo Mode

Solo is the default, and it's where most of AriCore's depth lives. The model can be local or cloud — every other capability (memory, personas, tools, browse) works identically across both.

Providers

Cloud BYO-key. Each provider is a (name, base URL, key) triple stored in the Keychain. Built-in templates: OpenAI, Anthropic, OpenRouter, Groq, an Ollama LAN endpoint. Custom OpenAI-compatible endpoints work too — point at the URL and provide whatever key the endpoint wants.

Models are fetched on add and refreshed on demand. Per-provider you can hide models you don't want to see in pickers.

Recommended starting points:

Both support tool calls + streaming and store keys exclusively in the iOS Keychain. If you want to mix and match, AriCore is happy with multiple providers configured at once — pick the model on a per-thread or per-persona basis.

On-device inference

The local engine is llama.cpp + Metal. Drop a .gguf file into the Files app and it appears in the Models tab. Each model row shows quant, parameter count, file size, and live RAM headroom. Tap one to load; the chat header shows a "On-device" tag.

iOS suspends the model when memory pressure is high. AriCore handles this gracefully — the chat blocks until the model can re-load. Airplane mode is a supported mode, not a degraded one.

The tool loop

Cloud models that support tool calls (most do) drive a multi-round loop: the model emits a tool call, the runtime dispatches it on the device, the result is fed back, the model continues. AriCore renders each tool call as an inline card under the assistant bubble — name, status (running / OK / failed), summary line, and a tap-to-expand body. The loop caps at ~12 rounds per turn as a safety net.

Approvals are per-tool: every tool that requires consent (anything that does something — drafts, calendar inserts, web actions) blocks the loop with an inline card showing the exact payload. Tap Allow or Deny. Optionally, "always allow this tool" persists the decision on the active persona.

Personas

A persona is a named collection of: a system prompt, a default model, an avatar, a memory bank, and a tool allowlist. AriCore ships with one ("Ari") and you can create as many as you want.

Why personas: different sides of your life want different defaults. A work persona that knows your colleagues' names, your team's projects, and never schedules things on Friday afternoons. A home persona that knows the dog's vet number and the kids' bedtime. A research persona that's read everything you've highlighted from a long Sunday of browsing.

What lives on a persona

Example use

Use case: separate work and home accounts. Create two personas. The work persona uses GPT-4o (your team pays), allows Mail / Calendar / Messages / Shortcuts, and has a system prompt that says "you're my chief-of-staff for the company". The home persona uses an on-device GGUF (privacy), allows Reminders / Shortcuts only, and has a softer voice. Each thread is bound to a persona; switching thread switches the model, the tools, and what Ari remembers about you.

Memory

Memory is per-persona, not global, and it's hybrid: a small cap (currently 25) of pinned + manually-saved + recent entries are loaded into every turn's system prompt. A larger underlying SwiftData store holds everything else, searchable on demand via the memory_search tool.

Memories are categorised. Facts, preferences and projects are durable — they stay until you remove them. Activity (added in v0.5.1) covers one-off context like "went to the gym today" or "shipped the v0.5 release Monday" — useful for a few days, irrelevant by next month. Activities fade from the per-turn injection block after a week and a half or so, then drop out of recall, and get pruned from the store later. Manual entries you save by hand sit alongside as a fifth, never-decaying category.

How memories get written

How memories get read

The per-turn prompt block holds up to 25 entries: all pinned ones, then the manual ones, then most-recent-first auto entries until the cap. Anything above the cap is reachable via memory_search(query) — Ari calls this when it needs to recall something not in the active block.

Incognito threads see no memory in either direction — nothing is loaded, nothing is extracted, nothing is written. The trust contract: an incognito conversation truly leaves no trace.

Editing memory

Open a persona's memory page from the persona editor. Each row shows the memory text, when it was extracted, and pin / forget controls. The memory bank is local to the device (SwiftData); nothing syncs.

Memories from dreams

The overnight dream pipeline proposes new memories alongside skills, personas, and watchers. They appear in the dream report screen for review — approve and the memory is written immediately into the persona that was reflected on; reject and it's discarded. Dream memories never apply silently.

The assistant-context block

Alongside the per-persona memory block, every Solo turn (except tutor chats and incognito) receives an assistant-context block injected into the system prompt. It carries the date and time, the user's timezone, today's calendar events (via EventKit, if granted), the current location and weather (via Core Location + Open-Meteo, if granted), the active Solar Hours phase, and a short pointer to the most recent thread. Sources gate themselves: declining the iOS location permission cleanly leaves the location/weather lines off. The block refreshes on every foreground transition.

Course tutor chats explicitly do not receive this block — tutors are scoped to course material and don't know what's on your calendar tomorrow. See Study.

iOS Tool Surface

Native iOS, not web reach-arounds. Every tool below is implemented against the platform API and gated by an approval card before it fires.

ToolWhat it doesAPI
calendar_createInsert an event into the user's calendar with title, start, end, location, notes.EventKit
reminders_createAdd a reminder with optional due date and list.EventKit
mail_draftOpen a Mail compose sheet with To/Cc/Subject/Body pre-populated.MFMailComposeViewController
messages_draftOpen Messages with a conversation pre-populated.MFMessageComposeViewController
shortcuts_runRun a Shortcut by name; results return via x-callback-url.Shortcuts URL scheme
weatherRead current conditions + 7-day forecast for the user's location.open-meteo (no key)
memory_searchSearch the active persona's memory bank for relevant entries.SwiftData FTS-style filter
browse_history_searchSearch the browsing history (Browse with Ari surface only) by URL or title substring.SwiftData
web_browseFetch a page in a hidden WebView and return body text + interactive elements. Allowlisted hosts only.WKWebView
web_planSilent scout — load a URL in the active browse tab and return interactive elements only. No body, no approval, fast.WKWebView (active tab)
web_actPlan-then-act page automation. Navigate / fill / click / submit / scroll / wait, with up-front approval card.WKWebView (active tab)
current_page_readRead the full body text of the active browse tab on demand.WKWebView (active tab)
watcher_createSchedule a conditional trigger (location enter/exit, calendar match, weather change, time of day).SwiftData + iOS background tasks
skill_*Any locally-defined skill the active persona has enabled. Each skill is a markdown body + JSON config; the runtime exposes its declared parameters as tool args. See Skills.Local skill registry
routine_propose / watcher_propose / persona_propose / memory_proposeDream-pipeline outputs. Not directly callable in chat — emitted by the overnight dream run for review on the dream report screen.SwiftData (proposal queue)

Permissions

Every iOS API has its own permission gate (Calendar, Reminders, Contacts, Notifications, etc.). AriCore requests them only when a tool actually needs them, and only with the user's approval — declining the iOS permission prompt cleanly returns a "denied" tool result to the model so it can route around. Permissions can be revoked at any time from iOS Settings; AriCore handles revocation gracefully.

Example use

Use case: morning planning. "What's my day look like?" — Ari calls weather for the forecast, calendar_create's read counterpart for today's events, and memory_search for any commitments it's been told about. It drafts a 5-line summary. If you say "remind me to leave at 8.45 for the dentist", it calls reminders_create with the right time. No tap-through to multiple apps, no copy/paste, just a conversation with consequences.

Skills

Skills are local, model-callable mini-tools. Each skill is a plain markdown document that describes what it does and when to use it, plus a small JSON config that declares its parameters. The active persona's enabled skills are exposed to the model as additional tool calls — the model sees them alongside calendar_create, memory_search, and friends.

Anatomy of a skill

A skill has four parts:

Skills are intentionally shaped templates, not arbitrary code. They can't make network calls, can't run shell commands, can't touch the filesystem on their own. What they do is canonicalise responses — turning "draft an email in my voice" or "convert these numbers into a markdown table the way I like it" into a one-shot tool call instead of a free-text request the model might fumble.

Creating a skill

Settings → Skills → +. You can author by hand, or have the model draft one from a description.

The isolation matters: skill bodies are themselves data the model can see when calling them. If your personal data leaked into the generator's prompt, that data could end up baked into a skill body and re-surface every time the skill runs. The isolated context guarantees that won't happen — the generator only sees your description, your stated parameters, and the skill schema.

Per-persona enablement

Each persona has its own enabled-skills set. A "writing" persona might enable a draft-newsletter skill; a "work" persona might enable a follow-up-email skill and a meeting-summary skill. The same skill can be enabled on multiple personas. The active persona's enabled skills are the only ones in scope for a turn — so your home persona doesn't have the work persona's tools.

Dream-proposed skills

The overnight dream pipeline can propose new skills — if the assistant noticed you ask the same kind of question every week, it might draft a skill that captures the pattern. Approval flows through the dream report screen and uses the same isolated generator as the manual From a description path. See Dreams.

Routines & Briefings

A routine is a scheduled prompt. Set it to fire daily, on weekdays, on specific weekdays, or once. At the scheduled time, AriCore wakes the active persona, runs the prompt, and posts the result as a fresh thread with a notification. There's a "From Ari" badge so you know it wasn't user-initiated.

How they fire

Routines run via an iOS app-refresh background task. On every backgrounding AriCore submits a fresh request with the next due fire time minus a small lead window — so when iOS dispatches the task it can run the model and overwrite the placeholder notification's body with the real reply before the user-visible fire time. If the OS doesn't grant background time, the placeholder fires as the fallback and the routine catches up on the next foreground.

iOS background tasks are best-effort — the system decides when (and whether) to dispatch. Real-time delivery would need a server, which is out of scope for Solo. For routines that must fire at an exact time, use a Shortcuts automation instead.

The daily briefing

A pre-built routine. Ari composes a short morning brief covering: today's calendar, today's weather, any unread reminders, anything from your memory bank tagged "today/this week", and optional sections you can configure (news, market, etc.). It posts as a thread you read with coffee. Configure in Settings → Briefing — schedule, sections to include, weekdays-only, etc.

Creating a routine

Settings → Routines → +. Pick the persona to wake, the schedule (daily / weekday / specific weekdays / once), the time, and the prompt to run. Optionally attach a notification preview ("Ari has your morning brief"); the notification is replaced by the model-generated thread title when the routine actually fires.

Watchers

Watchers are conditional triggers — they fire when a state changes, not on a clock. Configure them in Settings → Watchers, or have Ari propose one via the watcher_create tool. Approved watchers persist; cancel from the same screen.

When a watcher fires, AriCore wakes the persona with a short prompt describing the trigger, runs the model, and posts the result as a "From Ari" thread plus a notification. Live Activities support is built in for in-flight watchers — long-running ones (e.g. monitoring a forecast for the next two hours) get a Dynamic Island / lock-screen indicator so you can see status at a glance.

How they fire

Watcher evaluation runs on the same iOS app-refresh background task as routines, submitted on every backgrounding. The handler walks every active watcher, checks if its condition is met (against a small per-watcher cooldown to avoid spam), and dispatches the model turn for any that match. Same iOS best-effort dispatch caveat applies as routines.

Example use

Use case: it's about to rain. A weather watcher set to "rain expected within 2 hours, between 7am and 7pm". When the forecast flips, Ari wakes, glances at your calendar (anything outdoor today?), and drops a short note: "Rain forecast in the next hour or so. You've got the football pitch booked at 3 — want me to message the group?" Tap yes, it opens an iMessage draft via messages_draft.

Dreams

Dreams are AriCore's overnight reflection feature. While the device is plugged in and idle, Ari reads recent conversations, reflects on what it learned about you across the day or week, and gathers proposals — concrete things it thinks the assistant should know or do or become. Nothing applies silently; every proposal is presented for review.

When dreams run

Dream runs are scheduled by a BGProcessingTask with requiresExternalPower = true and requiresNetworkConnectivity = true. iOS dispatches the task whenever those constraints are satisfied — typically during the user's overnight charge. The pipeline self-arms: after each run completes (or is cancelled), the handler submits a fresh request so the chain perpetuates without user intervention.

You can also fire a dream manually from Settings → Dreams → Force dream now, or by tapping the Time to dream card on the threads screen when it appears in the evening / on first use.

What dreams read

The pipeline gathers dreamable conversations — threads from the active personas, excluding:

The pipeline runs persona-by-persona so proposals are correctly scoped — a memory drafted from your work persona's threads gets proposed against the work persona, not globally.

Four kinds of proposal

The dream card

A pinned card on the threads screen surfaces the dream feature in three states:

The card has a painted night-sky background (v0.4.3): crescent moon, orbital rings around a glowing sun, drifting clouds, mirrored on water below. The same artwork extends into the full dream report sheet so the feature has one consistent visual identity.

The dream report

A full-screen sheet that groups proposals by confidence bucket (high → medium → low). Each proposal has three actions:

The report persists across launches — close the app mid-review and pick it up the next morning. The proposal queue is SwiftData-backed.

What dreams don't see

Example use

Use case: notice a pattern. Over a week, you ask Ari three times to draft an email checking in with a recruiter after an interview. Tomorrow's dream proposes a recruiter_followup skill: parameters for the recruiter's name and the role title, body templating your preferred greeting and closing, no boilerplate that doesn't sound like you. Approve, the isolated generator drafts the skill body, you see a preview, accept, and from then on a single chat sentence triggers the right email.

Browse with Ari

The headline of v0.3 — a real visible browser inside Solo mode, with Ari sitting beside the page as a copilot. Tap the Browse tab on the bottom bar to land on it.

The surface

Top: a slim nav bar — Tabs button (top-left, with count badge), back, forward, URL bar, reload, home, menu (•••). Under that: an optional find-on-page bar that slides in. Then the WebView fills the screen. Bottom-right: a floating Ari orb — a small sun-disc circle with a soft corona that pulses while Ari is working. Tap the orb and the chat slides up; tap the chevron in the panel header to slide it back down.

Tabs

Each tab is independent — its own URL, its own scroll position, its own conversation with Ari, its own ad-block-applied WKWebView. The tab switcher (top-left button) shows a grid of all open tabs plus a "Recently Closed" section for one-tap undo.

Tabs persist across app launches: URLs, titles, and chat-IDs are written to UserDefaults on every navigation, restored on next open. Tabs the user never talked to come back un-chatted (no orphan threads in your THREADS list). Tabs the user did talk to come back with their conversation intact.

Long-press any link to "Open in New Tab"; new private (incognito) tabs use a non-persistent WKWebsiteDataStore so cookies / cache / localStorage evaporate when the tab closes.

Bookmarks & History

Bookmarks live in SwiftData. Each row has a title, URL, and an optional note field — free-text describing why you saved it. Notes are surfaced to Ari in the system prompt addendum so it can suggest "open the X bookmark" without you listing them.

History captures every navigation in Browse with Ari (deduped by URL with a visit count). Searchable from the History sheet (substring on URL or title) and from the URL-bar autocomplete (which shows bookmarks first, then dedupe-against-bookmarks history). Cleared from the menu's "Clear browsing data" action — wipes history, recently-closed-tabs, and Apple's WKWebsiteDataStore (cookies, cache, localStorage).

Configurable from the Bookmarks sheet:

Ad & tracker blocking

Always on. AriCore ships with a curated list of ~150 ad / tracker / analytics / consent-wall hosts compiled into a WKContentRuleList at first WebView mount and cached for the app's lifetime. Network requests to those hosts are blocked at the WebKit layer — they never reach the page. The list covers: Google ad stack, Meta, Amazon advertising, header bidders (Criteo, Pubmatic, Rubicon, AppNexus, etc.), Taboola/Outbrain, analytics (GA, Hotjar, FullStory, LogRocket, Heap, Mixpanel, Segment, Amplitude), consent-popup loaders (Cookiebot, OneTrust, Didomi, TrustArc, Consensu), push-notification networks. Plus generic CSS hides for common ad-slot containers and consent banners that survive the network block.

Reader mode

Strips chrome / nav / sidebars / ads from a page and presents the article alone in a typography-focused sheet. Heuristic extraction: scores article, main, [role="main"], and section elements by text density and paragraph count, takes the highest-scoring one, removes scripts / iframes / forms / buttons, and renders the cleaned HTML inside a stripped-down WebView with light/dark CSS that respects the system's color scheme.

The Ari surface

Three tools are reserved for the Browse with Ari context:

What Ari sees

Every turn in a Browse-with-Ari chat, the system prompt addendum injects:

One-tap shortcuts

From the menu, three pre-built prompts:

Privacy posture

Example use

Use case: shop a known product. "Add the cheapest Flipper Zero from currys.co.uk to my basket." Ari calls web_plan on currys.co.uk, sees the search box's selector. It composes a web_act batch: navigate, fill the search with "flipper zero", click submit, click the cheapest result, click "Add to basket". The approval card shows you all five steps. Tap Allow, watch the page drive itself with each element briefly highlighted before it's touched, end on the basket. Total time: 8-15 seconds depending on network. Pre-v0.3.1 the same flow took 30-60 seconds across multiple guess-and-retry rounds.

Study

Study is a top-level Solo tab for self-paced courses. You name a topic and a goal, set your daily time budget and course length, and Ari designs the curriculum and starts generating lessons. Each course runs as a series of structured sessions: a lesson body, a quiz, optional activities, and (at the midpoint and end) cumulative exams.

Creating a course

Tap + on the Study screen. The form takes five inputs:

The form is the whole input. There's no chat with Ari to negotiate the curriculum — submit it and Ari designs the spine in the background.

The curriculum spine

A spine is the destination arc: an ordered list of modules, each with named concepts. It isn't a fixed lesson plan — lessons themselves are generated session-by-session, informed by what you covered, where the quiz revealed gaps, and which flashcards you're failing. The spine is visible at the top of every course screen and lists the exact session numbers where the midpoint and final exams will fire.

The generator is volume-aware: depth scales to total hours of learning time, not just calendar days. A 21-day × 30-minute bootcamp produces meaningfully harder material per session than a 21-day × 5-minute overview. Module counts, quiz lengths, and activity inclusion all scale with the budget.

A session

Every regular session has at minimum:

On top of that, the generator can include optional activities (only when they fit the topic and the budget — otherwise omitted entirely, no placeholder cards):

The lock-in flow

Activities don't submit on their own buttons. Each card has a lock in action that freezes the answer; the lesson body stays visible while you work through the rest. When you've locked everything, COMPLETE LESSON at the bottom of the pack commits the whole session in one shot — quiz is persisted, free-response and code answers are graded asynchronously, the screen flips to a post-completion view with a soft grading shimmer until the marks land.

Midpoint and final exams

Exams fire automatically at half the spine's session count and at the end. Format is multi-choice plus free-response, cumulative on everything taught up to that point, with the tutor writing prose feedback on the written answers. Threshold to pass is 70%.

Fail an exam and you get a fail grade plus an option to extend the course. The tutor identifies the weak topics from your answers, generates a focused remediation arc (5 extra sessions for a failed midpoint, 8 for a failed final), and the exam re-runs at the end.

The per-course tutor

Every course has its own chat — tap Chat with your tutor on the course screen to ask about the lesson. Tutors are not personas. They live separately in the Study tab and can't be selected from the persona switcher. Hard wall around your personal context:

If you ask your Italian tutor "what's on my calendar tomorrow?", it answers like a tutor would: don't worry about that now, we'll get to it tomorrow.

Overnight lesson generation

Next lessons are pre-generated by a BGProcessingTask with requiresExternalPower = true — typically during your overnight charge. The post-completion footer is honest about it: "We'll prep your next lesson while your phone is plugged in tonight." Tomorrow's session is on disk before you wake up, so opening Study is instant.

If you can't wait, the same screen offers a BEGIN NEXT SESSION NOW button that triggers live generation right there. Foreground generations are wrapped in a UIApplication.beginBackgroundTask grace window (~30 s) so a quick backgrounding doesn't kill the call.

Certificate, workbook, branching

Finish a course and the celebration screen leads with a framed certificate: double gold border, ornament strips, a wax-seal medallion holding your final-exam grade letter, the date awarded. It springs in on first view with a soft scale + fade and replays whenever you re-open the completed course.

The same screen offers two follow-ons:

Completed courses

Completed courses stay visible — a Completed section at the bottom of the Study tab keeps every finished course one tap away for re-export, re-reading the certificate, or branching into a follow-up later.

Example use

Use case: prep for a trip. "Conversational Italian, daily 10 minutes, 42 days, no prior knowledge." Ari spins a 12-session spine. Each morning you open Study, read a short lesson, work through a quiz and a 4-blank cloze passage in Italian, lock both in, tap COMPLETE LESSON. At session 6 a midpoint exam fires — multi-choice plus a written answer where you have to compose two sentences. Tutor grades, gives a B+. By session 12 the final exam asks you to write an introductory paragraph in Italian. You pass at 78%, get the certificate, export the workbook as a PDF to take with you, and Ari proposes "Italian for dining and travel" as the next course based on what you said you wanted more of.

Themes & Solar Hours

AriCore ships with two free palettes (Paper, Midnight) and eight paid IAP palettes (Slate, Vellum, Ink, Linotype, Foxglove, Verdigris, Crow, Manuscript). Each palette is a complete (bg, surface, card, ink, accent, accent-cool, accent-desk) token set; switching theme retints the entire app instantly.

The palettes

PaletteIdentity
Paper (free)Warm cream + gold accent. The original.
Midnight (free)Dark "Golden Thread" — matches the website's dark mode.
Slate (IAP)Cool blue-grey, architectural calm.
Vellum (IAP)Pinks and clays — art-journal palette.
Ink (IAP)Black on paper, all restraint.
Linotype (IAP)Cyanotype blue + press-blue ink. Hot-metal type.
Foxglove (IAP)Saturated lilac + magenta-purple. Deep bloom.
Verdigris (IAP)Saturated jade + tropical teal-green. Glasshouse.
Crow (IAP)Brick-blood + white + black. Cinema poster.
Manuscript (IAP)Honey amber + aubergine purpura + lapis. Illuminated.

Solar Hours cosmetic

An optional IAP cosmetic that adds a daily-rhythm layer to the masthead. Three components:

Purchasing

StoreKit 2, on-device verification. Tap a locked theme in the picker → buy sheet → instant unlock. Restore Purchases lives in Settings; entitlements derive from Transaction.currentEntitlements on every launch so they survive reinstalls.

Voice Mode

Voice runs entirely on-device. There is no cloud round-trip for either speech-in or speech-out — your microphone audio never leaves the phone.

The stack

Using it

The composer has a microphone button alongside the text field. Hold to talk; release to send. Tap-and-lock turns it into a continuous-listen mode that ends the turn on a silence threshold. Assistant bubbles get a small "read aloud" affordance — tap and Kokoro reads the reply in the chosen voice.

Voice mode is on a free per-day quota for the on-device path; nothing to configure. The Kokoro voice picker lives in Settings → Voice.

Linked Mode & Pairing

Linked mode connects AriCore to an aricode desktop. On the desktop, run:

aricode companion pair

A QR code prints in the terminal. Open AriCore on the phone, tap Link to desktop, and scan. Both screens show a short fingerprint — verify it matches, then accept. The relay URL, device identity, and shared key are stored in the iOS Keychain, device-bound, and never leave the device.

After pairing, the Linked tab populates with your active aricode sessions. You can send prompts, watch streaming replies, see tool calls as inline cards, and approve / deny privileged ops from the phone. The desktop loop blocks until you answer.

Pairing supports multi-device: N phones / iPads to one Mac. Revoke any one without touching the others from the desktop's Devices panel.

Desk Mode PREVIEW

Desk mode turns aricode into a personal-agent runtime alongside its coding-agent mode. Named agents run on your Mac as host processes pinned to a per-agent workspace, gated by an approval broker. You manage them from the desktop's Desk tab and chat with them from the AriCore app like a group thread of teammates. Each agent has:

On-disk layout

Each agent has its own directory containing its persona files, rolling memory, a searchable history, scheduled-task config, a pinned workspace for shell + file operations, and a persistent Chromium profile. Alongside the agents, the desk layout holds shared templates, global skills, an MCP server registry, an approvals audit log, and the "always allow" rules. The agent directories are safe to version-control (minus the browser profile, the recall index, and the history) — you can sync personas between Macs.

CLI

The desktop's Desk tab is the primary surface; the CLI is for scripting and headless setup.

CommandPurpose
aricode desk initScaffold the desk runtime directory and copy seeded templates.
aricode desk new <slug> [--template research]Create an agent from a template; opens its persona file in $EDITOR.
aricode desk listAgents with status: last-active, runtime state, model, weekly token usage.
aricode desk edit <slug>Open the agent's config directory in $EDITOR.
aricode desk logs <slug>Tail stdout/stderr from the most recent session.
aricode desk startBoot the Desk runtime (relay + broker + registry). Foreground.
aricode desk stop <slug>Force-stop a running agent.
aricode desk doctorCheck the broker, relay connectivity, configured model keys, the Playwright Chromium install, and writeability of the runtime directory.

Toolsets

Each agent declares its capabilities by referencing toolsets in agent.md frontmatter. Deny always wins over allow.

ToolsetTools
browserCDP via Playwright with a per-agent persistent profile: navigate, click, fill, extract, screenshot, snapshot, wait_for.
terminalterminal.run(cmd, cwd, timeout_ms) pinned to the agent's workspace/. Pre-classified by the exec policy into auto, gate, or deny.
filesfile.read, file.write, file.edit, file.search scoped to workspace/; paths above it are refused before they reach the FS.
webBrave Search API (host-side).
hostAppleScript broker — sends {script, description} to the host, routes approval to the phone, returns the result.
mcpTools surfaced from MCP servers in mcp.json (stdio, SSE, or streamable-HTTP transports), namespaced as mcp.<server>.<tool>.
minimalJust memory.update. Useful baseline for conversational personas.

The approval flow

Every gated tool call passes through three tiers before it fires: the workspace pin rejects paths above the agent's pinned cwd; the exec policy classifies shell commands as auto (safe reads), gate (asks once, can be remembered), or deny (foot-guns, never run); and the approval broker checks the local rules file for a scoped whitelist match. If none match, the agent blocks until you respond from the desktop or phone. "Always allow" is scoped by call kind and target — e.g. imessage.send to +44…0001 — never a blanket yes.

Every invocation (approved, denied, auto-whitelisted, timed-out) is appended to a local audit log with a timestamp and decision source. Clear the rules file at any time to revoke all whitelist entries.

The gate

The agent runs as a host process pinned to its workspace; isolation comes from the three-tier gate (pin · exec policy · petition) plus the append-only audit log. Container-grade sandboxing is a long-horizon roadmap item — the current discipline is to make every privileged call visible and declinable rather than to rely on rootfs walls. Agents load lazily on the first message and idle out after roughly an hour of silence; the browser context closes with them, so a sleeping agent costs no CPU and no tabs.

On the phone

The AriCore Desk tab appears only when the paired desktop advertises capabilities.desk: true. Inside it:

iOS suspends the WebSocket when the app backgrounds, so AriCore resyncs agent state and re-opens the active chat on every foreground. No frames are lost.

Not yet in this preview

Deferred to later releases: APNs push for unsolicited agent messages, image / video / music generation tools, voice mode, agent-to-agent delegation, Windows / Linux hosts, a bundled LaunchAgent installer, container-grade sandboxing.

Sessions & Artifacts

aricode persists both workspace-global and project-local artifacts so that it can resume context across restarts.

Path Purpose
~/.aricode/{workspaceHash}/session.jsonModel, backend, config, and session metadata.
~/.aricode/{workspaceHash}/transcript.jsonlConversation history.
~/.ariadne/{workspaceHash}/summary.mdPersistent session summary for later reuse.
.aricode/ARICODE.mdProject memory injected into turns.
.aricode/graph/Knowledge graph data and related indexes.
.aricode/dream/Dream journal, findings, futures, and related exploration artifacts.
.aricode/plans/Approved or pending plan files.

Because sessions persist, commands like /history, /new, and /reset matter operationally. They do not just affect the visible transcript, they affect how much prior state aricode carries forward.

Session Persistence

aricode automatically saves your conversation so you can resume where you left off.

CLI session resume

In the CLI REPL, conversation messages are saved to conversation.jsonl alongside the existing session files. On next launch:

When resuming, a banner shows: ◈ Resumed · 14 messages · last active 2h ago

Desktop session management

The desktop app saves sessions to ~/.aricode/desktop-sessions/. Each session is a single JSON file keyed by a persistent id, plus a shared index.json for fast listing. Writes happen:

When you open a workspace, the app auto-resumes its most recent session if it was saved within the last seven days; otherwise it creates a fresh one. The sidebar's Sessions tab is filtered to the currently-open workspace only — sessions from other projects never mix in. The currently-active session is highlighted with an amber thread marker and pulsing ; idle sessions reveal a delete button on hover.

Up to 50 sessions are retained across all workspaces. Each session file stores the SDK snapshot (messages, file read log, scratchpad, command log) plus metadata (workspace path, model, timestamps, first-message preview). The renderer receives a broadcast aricode:sessions-updated event on every save so the sidebar list refreshes live.

Shared configuration

Both the CLI and desktop app read from the same provider configuration file at ~/.aricode/providers.json. If you set up a provider in the desktop app, it's available in the CLI and vice versa.

Environment Variables

aricode reads the following environment variables. The ARICODE_* prefix is preferred; ARIADNE_* is accepted for backwards compatibility.

VariablePurpose
ARICODE_MODEL / ARIADNE_MODELDefault model name (overrides provider config)
ARICODE_BASE_URL / ARIADNE_BASE_URLDefault backend URL
ARICODE_API_KEY / ARIADNE_API_KEYAPI key for the backend
ARICODE_PROFILE / ARIADNE_PROFILEOutput profile: compact or balanced
ARICODE_LANG / ARIADNE_LANGTarget language hint
ARICODE_PRIVILEGED=1Start in privileged command mode
ARICODE_CONTEXT_TOKENSOverride context window size (e.g., 128000)
ARICODE_DREAM_BASE_URLSeparate backend for dream mode
ARICODE_DREAM_MODELSeparate model for dream mode
ARICODE_DREAM_API_KEYAPI key for dream backend
ARIADNE_DEBUGEnable debug logging (verbose API/streaming output)
ARIADNE_ALT_SCREEN=1Use alternate terminal screen buffer (full-screen TUI)
OPENAI_BASE_URLFallback backend URL (lowest priority)
OPENAI_API_KEYFallback API key (lowest priority)
NO_COLOR=1Disable ANSI color output

Environment variables are overridden by CLI flags, which are overridden by /model and /backend commands in the REPL.

Languages & Environment

aricode supports a mixed-language world model and parser stack. The current language surface includes JavaScript, TypeScript, Python, Go, Rust, Java, Kotlin, Swift, C, and C++. The level of support varies:

LanguageParsingLintingConventions
JavaScript / TypeScriptFull ASTESLint + TypeScript parserFull
PythonFull ASTPyrightFull
Go, Rust, Java, KotlinSymbol extractionNone (uses model judgment)Partial
C, C++, SwiftSymbol extractionNoneBasic

The command policy recognizes many development toolchains, including npm, yarn, pnpm, bun, cargo, go, python, node, git, make, and related tools.

Troubleshooting

Model seems weak or unreliable

Use a stronger coding-capable model first. Many issues attributed to aricode are actually backend model failures in tool selection, long-horizon reasoning, or code synthesis quality.

Knowledge graph is stale or missing

Run /graph stats to inspect current graph state. If the project was never initialized, allow the initial graph build. If you need a fresh start, rebuild or reset the workspace state.

Agent keeps asking for approvals

That usually means the requested task crosses from read-only activity into mutating or privileged command tiers. Use /privileged on only when you intentionally want the agent to access a broader command surface.

Dream artifacts are missing

Run /dream directly and inspect .aricode/dream/. If your session never entered dreaming or was interrupted early, the artifacts may simply not exist yet.

Session context feels confused

Use /new to start a fresh conversation in the same workspace, or /reset to clear broader workspace state if you need a clean baseline.

The safest default workflow for serious code changes is: /init, /graph stats, /plan ..., review the plan, execute, inspect /diff, then /apply.