Skynet guide

Every screen, shortcut, right-click menu and setting — the same guide ⌘? opens in the app.

For R42-2026-09-30 · also at ~/Skynet/GUIDE.md on a Mac that has Skynet

Skynet is a Mac app for working with AI agents. An agent is a folder: its prompt, its settings, its memory and whatever it makes all live in that folder, as plain files you can read and edit. The app runs the agent through one of three engines — claude, codex or pi — and shows the conversation.

Open this guide with ⌘?, from Help → Skynet Guide, or with the ? at the bottom of the sidebar. The field at the top finds a word or phrase as you type: every place it occurs is marked, the page jumps to the first, ⏎, ↓ or ⌘G goes to the next, ⇧⏎, ↑ or ⇧⌘G back, and Esc clears it. The same file is kept at ~/Skynet/GUIDE.md, so an agent can read it too. It is rewritten from the app on every launch, so edit the app's copy, not that one.


The window

The window has three columns — sidebar, chat list, chat — or two when a page (Dashboard, Automations, Telegram, Search) is showing: sidebar and page.

Row What it is
Dashboard Panels of your own — HTML files or commands that print HTML. See Dashboard.
Activity One glance at the whole app: which agents are doing something, how much, and what waits on you. Its mark is the app's load: a pulse while anything runs, amber at the turn cap or with a subscription above 75 %.
Telegram Write to your agents from Telegram on your phone. Green dot while your bot answers you.
Search Every chat in every agent, all three engines, plus the archive.
Favourites Your favourite agents, numbered 1–9 for ⌘1–⌘9. Always alphabetical, so the numbers stay put.
Groups Sections of your own — right-click an agent › Move to Group. An agent is in one place: in its group, and not listed again below. Right-click a group's name for Rename, Move Up, Move Down, Collapse All, Expand All and Remove Group; removing a group sends its agents back to Other agents, and a group whose last agent leaves goes by itself.
Other agents Everyone who is neither a favourite nor in a group. With no favourites and no groups there are no headers at all: the list is the list.
the line with Latest / A–Z One switch for every group and Other agents: Latest puts the agent that worked last on top, A–Z is alphabetical. It sits under Favourites, which keep their own order.

Every section folds: click its name. A folded section keeps the agent you have open in view, and its name carries one mark for each kind of thing the hidden agents have — the same marks as the rows, most urgent first — so nothing that needs you can hide in a fold. | Add agent… | Pick a folder — any folder, or make a new one — and it becomes an agent. Dropping a folder on the sidebar does the same. |

The mark on the right of an agent says what it is doing. Three colours, one meaning each: green is moving, amber is something for you to do, red is something that failed.

Mark Meaning
pulsing green dot running now — a turn, a check, a plan, a scheduled run
still amber dot, on an agent with work in flight retrying — the API is not answering. The engine is trying the call again, or a turn that failed is waiting for its next attempt. Nothing for you to do; it says so because nothing is being done
hollow green ring answered, but background work — a bash job, a subagent — is still going
amber hand answer it — a question on screen, or a task stopped for a word from you
amber check review it — a task finished and checked, waiting for Done
amber dot read it — a reply, or a run that went fine, not yet seen
red dot fix it — a turn error, a failed run, a check that cannot run, not yet seen
pencil an unsent draft (shown only for agents you are not on; sits before whatever mark the row has)

One slot per agent. When several things are true the higher one shows: hand, check, red, retrying, pulse, ring, amber dot. Your desk first, then what is moving, then what is only to read. A dot clears only when you open that chat or run — its row in the list, a notification, a search hit — not by arriving at the agent with it on screen. Catch Up on the agent's right-click menu clears them all at once. The same marks mean the same on a chat row and under the Automations and Autopilot sections. A failed run or a check that cannot run is red on its agent's row, not anywhere else — the sidebar's Activity item carries only the app's load.

Chat list

There is no rename or delete: a chat's title is the engine's own title for it, or its first message.

Chat

A new chat opens on a greeting and the agent's quickstarts — buttons that fill the message box for you to finish. They never send on their own.

In the conversation:

Message box

The chip bar under the box sets how the next turn runs. Every change is saved to the agent at once.

Chip What it sets
new chats which engine and which subscription new chats in this agent run on — claude (the default login), claude hh and any other named account, codex, pi — each listed with how full that plan is. A chat that has started is pinned to what made it, so the chip states it and offers no choice.
model the model — this chat's own. Each chat keeps the model it started on, so switching it here never changes another chat, on this engine or any other. In a new chat, before the first message, it sets the agent's default instead, which every new chat (automations too) starts on. default means whatever the engine is set to use; Other… takes any name.
effort / thinking how hard it thinks. Levels depend on the engine and model.
speed codex only, on models that offer a service tier.
permissions claude only: run tools (everything runs), ask first (each tool waits for Allow/Deny), plan first (a plan to approve, then it runs).
context meter how full the conversation is. Amber over 70 %, red over 90 %. Hover for tokens and cost.

The round button sends; while a turn runs it becomes Stop (⌘.). Stop twice ends the session.

Toolbar

Everything up here is about the agent in front of you. In from the right edge:

The two controls that are about the app rather than about an agent — the gear (App Settings) and the ? (this guide) — are at the bottom of the sidebar, beside + Add agent…. ⌘, and ⌘? reach them whether or not the sidebar is showing.


Keyboard shortcuts

Keys Action
⌘N New chat
⌘1 – ⌘9 Favourite 1–9
⌘O Switch to any agent: every agent A–Z, or type part of its name, then ↑/↓ and ↩︎. The agent you were just on sits on top, so ⌘O ↩︎ goes back to it.
⌘0 Dashboard
⌘S Activity
⌘T Telegram
⌘F Search every chat
⌘K Search this agent's chats
⌘L Go to the message box
⌘↑ / ⌘↓ Previous / next chat in the list (also works in the message box)
⌘I Agent Settings
⌘, App Settings
⌘? This guide
↩︎ Send, or queue while a turn runs
⌘↩︎ Send
⇧↩︎ New line in the message
⌘. Stop the turn; again to end the session
↑ / ↓ In an empty message box: your earlier messages. In the / or @ menu: move.
Tab Pick the highlighted / or @ row
Esc Close the / or @ menu

Right-click menus

On Items
an agent Catch Up — N unread (when there is something to clear), Add to / Remove from Favourites, Move to Group › (the groups, New Group…, Remove from Group), Edit Icon…, Open in Zed, Open Terminal Here, Show in Finder, Rename…, Close…
a section name Collapse All, Expand All — and on a group: Rename…, Move Up, Move Down, Remove Group
a chat Pin to top / Unpin, Rename…
a card Open, Open in Browser (HTML/SVG), Quick Look, Show in Finder, Copy reference
a link chip Open in the other browser, once

Close only takes an agent out of the sidebar. The folder and everything in it stays; add it again any time.


Agents

Any folder can be an agent. Adding one writes a starter CLAUDE.md if there is no prompt yet. What the app keeps in the folder:

File What it is
CLAUDE.md Who this agent is. Read by every engine. In a git repo it is the repo's own and the app never writes it.
AGENTS.md A link to CLAUDE.md, for the engines that read that name.
.skynet/SKYNET.md What Skynet adds — contexts and anything only this Mac should know. Given to every engine and to the agent's subagents.
.skynet/settings.json engine, the model new chats start on, effort, speed, permissions, account, extra folders, parallel — and Autopilot's tasks (on/off), shift (all, day, night), pursue (tasks, goal, unattended), paused, sessionsPerDay (0 is unlimited)
.skynet/quickstarts/*.md the quickstart buttons
.skynet/automations/*.md what runs on a schedule
.skynet/tasks/*.md, .skynet/goal.md, .skynet/tasks/declined.md, .skynet/tasks/plans.json the task list, the goal, the proposals you dropped, and the log of planning runs
.skynet/links.md the toolbar's link chips
.skynet/box.yml the agent's development box — a container with its own localhost — if it has one
.skynet/memory/ the agent's memory, shared by all three engines
.skynet/files/ files dropped in from other apps
.skynet/logs/ logs of command automations

All of .skynet/ is plain files. Changes take effect at once — no restart.

Favourites: right-click → Add to Favourites. The first nine get ⌘1–⌘9, and the window opens on ⌘1.

Groups: right-click → Move to Group › New Group…, give it a name, and the agent is in it. The groups are kept in ~/Skynet/sidebar.json, with which sections are folded.

Rename: right-click → Rename…. An agent is a folder, so this renames the folder where it stands — and takes its chats with it. That last part is why the menu item exists: all three engines file an agent's chats under the path it had, so renaming the folder in Finder leaves every past chat behind, still on disk but no longer reachable from the agent. Renaming here moves claude's and pi's chat folders and rewrites the folder recorded inside each codex thread. An agent that is working will not rename — let the turn finish first — and any session it has open is closed, which costs nothing: the chats reopen from disk.

Another agent's folder can be pulled into a message with @agent: it inserts the folder's path, and the agent reads its prompt, settings and files from there.

Prompts, contexts and memory

Every turn is built from, in order:

  1. ~/Skynet/SKYNET.md — the prompt every agent shares. Edit it in App Settings → System prompt.
  2. The agent's CLAUDE.md.
  3. The agent's .skynet/SKYNET.md.

Contexts are facts several agents need — "personal", "company". Each is a file in ~/Skynet/context/. Put @context/<name>.md in an agent's .skynet/SKYNET.md and it is included on every turn. Manage them in App Settings → Contexts.

Memory is .skynet/memory/: one fact per file, and MEMORY.md as the index. All three engines read and write the same folder, so what one learns the others know.


Engines and accounts

Engine What it is
claude Anthropic's CLI. Subagents, plan mode and permission prompts — everything the app can drive.
codex OpenAI's CLI on a ChatGPT plan. Delegates to subagents. Runs unattended: no permission prompts, no plan mode. Offered only when codex is installed and signed in.
pi Other providers (zai, minimax, kimi, xiaomi) on their own quota. No subagents and no permission prompts.

A chat keeps the engine it started on. New chats and every automation in an agent use the agent's engine (Agent Settings → Engine, or the engine chip).

Chats run in parallel (Agent Settings → Engine) lets every chat in the agent run a turn at the same time, instead of one at a time. Off by default, because all chats share the folder with full write access: two turns can edit the same file or both commit. Turn it on for agents whose chats mostly read and write their own separate files. The app-wide cap of 10 running turns still applies.

An upstream "API Error" is retried after 1, 4 and 10 minutes. While that goes on the run or chat says Retrying in amber, with the reason and the attempt — "Can't reach the API · attempt 3 of 10" while the engine retries inside the turn, "next try 09:15 · attempt 2 of 3" while the app waits to send the turn again. A scheduled run keeps its row under Automations the whole time and is only called failed by the attempt that ends it.

Several Claude accounts

More than one Claude subscription can be signed in at once, and Skynet treats them as one pool. An agent is set to one of them (the engine chip, or Agent Settings → Engine), but when that plan passes 70 % on either bar a turn borrows whichever other account has the most room and goes back when the window resets. The badge in the toolbar always names the account that is actually paying — with ↩︎ when it is borrowing. When every plan is spent the chat is parked: it says so, you get a notification, and it resumes by itself when the plan resets.

Adding one. Pick a short name — it is what you will see in the menus — then in a terminal:

mkdir -p ~/Skynet/accounts/<name>
CLAUDE_SECURESTORAGE_CONFIG_DIR=~/Skynet/accounts/<name> claude

and /login inside it. Skynet finds it the moment the folder exists; the login is what makes it usable. Every folder under ~/Skynet/accounts/ is an account, and the folder's name is the account's name.

All of this is only for the extra accounts. The default account is a bare claude — the login you already have, in its usual place, with nothing set up and nothing redirected. It has no folder under ~/Skynet/accounts/ and never needs one.

Only the credential is separated, nothing else. CLAUDE_SECURESTORAGE_CONFIG_DIR redirects where the CLI keeps its OAuth token and nothing more, so every account — default and named alike — shares one ~/.claude/: the same settings, skills, MCP config, projects and transcripts. That is why an account's folder stays empty, and why a chat started on one account reads the same as a chat started on another. The only thing that changes is which subscription is billed.

Each machine logs in separately. The credential is not in the folder — the folder stays empty. It is in the login keychain, under Claude Code-credentials for the default account and Claude Code-credentials-<hash> for a named one, where the hash is the first 8 hex of sha256 of the folder's absolute path. So there is nothing to copy across: syncing ~/Skynet/accounts/ copies empty folders, and the keychain item stays behind. On a new Mac, run the two lines above again for each account.

(The item could in principle be moved with security, but only if the path hashes to the same value — which means the same username — and the token it holds is rotated by the CLI anyway. Logging in again is two commands and always correct.)

Which accounts exist is whatever is in ~/Skynet/accounts/ plus the default. Removing an account is removing its folder; the keychain item it used is then unreferenced and can be deleted in Keychain Access, or left alone.


Settings

App Settings (⌘,)

Tab What it holds
System prompt ~/Skynet/SKYNET.md, shared by every agent and by claude, codex and pi in the terminal. Saved as you leave the tab.
Contexts The shared fact files, which agents use each, and + for a new one.
Skills Every skill on disk — global, pi, plugins, and each agent's own. Search, open in Zed or Finder, edit SKILL.md, or + a new one.
Keys Each skill's .env. Saved as you type. These are secrets in plain text — don't open this tab while sharing your screen.
Setup Is this Mac ready? Each engine and its login (every Claude subscription, codex, pi), the Mac permissions agents need (Accessibility, Screen Recording, Notifications, Automation), bun, python3, uv, Homebrew, peekaboo, gh, your agents (a Mac with none gets a starter assistant), the global prompt linked for all three engines (a Mac without one gets the default that ships inside the app), the skills, and Zed with an optional config that also ships inside the app. Each installed tool also shows its version and, when its publisher has a newer one, "— x.y.z is out" with an Update button that runs the tool's own updater (claude update, codex update, pi update, bun upgrade, uv self update, brew upgrade). That is looked up once a day (the npm registry for the engines, GitHub releases for bun and uv, Homebrew's own list for the rest) and said only when known — offline, the row just shows what is installed. A claude older than 2.1.255 is flagged, because Fable 5.1 needs it and a chat pinned to Fable fails on an older CLI with "may not exist or you may not have access". Nothing is fetched from anywhere but each tool's own installer. ✅ ready, ⚠️ worth fixing, ❌ agents need it. Fix opens System Settings at the right pane, makes a small change to a file (always keeping a .before-skynet backup), or opens Terminal with the install or login command already running, so you see everything that gets installed. The page checks again when you come back to Skynet. Add & log in creates a new Claude subscription. Send test on Notifications posts a test notification, to check banners and Focus let it through. The sheet opens on this tab by itself at launch when there are no agents yet, or when claude or bun is missing.

Agent Settings (⌘I)

Tab What it holds
Prompt CLAUDE.md (locked if git tracks it) and the .skynet/SKYNET.md layer.
Engine Engine, Chats run in parallel, model, effort, speed (codex), and Claude account.
Autopilot The switch — off for every agent until you turn it on — then the agent's goal, when it runs (all day, day shift, night shift), and what it does when the queue is empty: Stop, Pursue goal — plan, wait for approval, or Pursue goal — plan and execute, no approval.
Folders Extra folders the agent may read and write, one per line. Its own folder is always included. (claude and codex; pi ignores it.)
Quickstarts Title, prompt, and hidden instructions for each button.
Automations Name, schedule, and prompt or command for each. Try in chat puts a prompt in a new chat without sending it.

Done saves Prompt, Engine and Folders. Quickstarts and Automations save as you type.


Quickstarts

One file per button in .skynet/quickstarts/:

---
title: Weekly review
---
Walk me through last week and pull out what actually mattered.

<!--hidden
Read .skynet/context first. Be brief.
-->

title: is the button. The body goes into the message box for you to finish. Anything between a line <!--hidden and a line --> goes to the model with every turn of that chat and is never shown. Optional: order: to sort. The body may be empty if the hidden part says it all — the button then just arms those instructions and leaves the box empty.

Automations

One file per automation in .skynet/automations/:

---
when: weekdays 08:30
name: Standup notes
---
Check my calendar and summarise the day.

when: is schedule words, then a local time:

Words Runs
(none), daily, every day every day
weekdays Monday–Friday
mon wed fri, weekly mon, every tue those days
monthly 1, monthly 15, monthly last that day of the month (monthly 31 means the last day in shorter months)

A prompt runs as a fresh chat of the agent, on its engine, with a note that nobody is watching — questions are declined automatically. If the agent is busy it waits for it — or, with Chats run in parallel on, runs beside it (the same automation never runs twice at once).

A command needs no model at all: add run: and it runs through zsh in the agent's folder, even while the agent is busy. The body is then just notes. Logs go to .skynet/logs/; the last 30 are kept.

---
when: sun 13:00
name: Trend sync
run: cd scripts && bun run sync.ts
---
Weekly pull. Deterministic, so no model needed.

Every few minutes instead of a time. Replace when: with every: — every: 5m, two minutes being the floor — and optionally on: for the days and between: for the hours:

---
every: 10m
on: weekdays
between: 09:00-17:00
name: Inbox sweep
---
Anything in the inbox that needs an answer today?

every: means not oftener than, not "this many times a day": one that comes round while the agent is mid-turn is dropped, not queued — the next one is minutes away and will see whatever is true then. With no between: it fires at 04:00 too.

A pull is the third kind: a check that decides whether the prompt runs at all. Add check: with a command, and

stderr never counts as output; it goes to the log, so a warning line from a tool cannot be mistaken for news.

---
every: 5m
on: weekdays
between: 09:00-17:00
name: PRs waiting on me
check: ./.skynet/checks/prs.ts
---
A pull request is waiting for my review:

Read the diff, leave review comments, then say in one line what you did.

The check is your own program — write it as a small .ts and run it with bun. It gets the agent's folder as its working directory and the same environment a turn gets, so gh, a skill or a token all resolve. Keeping track of what it has already reported is the check's job, not the app's: print a line per thing that needs doing, keep the ids you have reported in a file of your own, exit 0.

Automations fire only while Skynet is open, and never on a sleeping Mac. A Mac asleep with its lid closed still surfaces for a few seconds every ten minutes or so, and work started there runs in those slices — slowly, and with failed calls. So Skynet starts nothing by itself until the Mac has been awake for three minutes without a break: no automation, no check, no Autopilot task, no retry, no message from Telegram. What came due in the meantime shows as Queued · the Mac was asleep and starts by itself; a key or a click in Skynet starts it at once, because somebody at the Mac means it is awake. What you send from the message box is never held. A turn that was already running when the Mac went to sleep is not stopped. A time missed while the Mac slept still runs later that day; a missed day is not caught up, and an interval simply resumes. Unknown words make the automation invalid and it is skipped — the Automations tab shows it in red.

On an agent's Automations page (the Automations row in its chat list): one row per automation with when it runs and its last run; click one for its runs, with Try in chat, Run now or Check now, and Edit in the header, and a red dot after the name when the last run failed or its check cannot run — fine is silent. Add is top right. A command's runs are its logs.

Autopilot — tasks, plans and the heartbeat

Automations are fixed prompts on a clock. A task is a piece of work an agent does while you are away, and the heartbeat is what keeps it going. Off for every agent until you turn it on: Agent Settings → Autopilot. It is the agent's own — there is no list across agents.

A task is a chat with a status. One markdown file each in .skynet/tasks/: a name: and status: in the header, then two pieces of prose — what to do and why, and under ## Done when, how to tell it is done. The file is the ticket; the chat is the work. A task written by hand needs only that much — drop it in and it is queued:

---
name: Write a haiku file
status: queued
---
Write .skynet/files/haiku.txt holding a three-line haiku about the sea. Nothing else in the file.

## Done when
.skynet/files/haiku.txt exists and has exactly three lines

The app adds the rest as it works — created, by, chat, engine, turns, checks, checker, verdict, note, updated — and plan on a task a planning run proposed. To set an agent up entirely from files: "tasks": true in .skynet/settings.json (with shift, pursue and paused as you like), a .skynet/goal.md, and task files in .skynet/tasks/. Anything you write into a task's chat, whatever its status, puts the agent back to work on it — that is how you answer, send back, or reopen.

The six statuses, in the order a task moves through them. One word each, the same everywhere.

Status Means Gets there by Leaves by
Proposed the agent suggested it a planning run Accept → Queued · Start now → Working · Drop → gone, and never proposed again
Queued waiting for the heartbeat Add, Accept, Pause, Back to the queue, a check script the heartbeat takes the oldest → Working · Start now · Move to top
Working the agent is on it the heartbeat, Start now, or your message it asks you → Waiting · it says finished → the check runs → Done on a pass, or Review when there was nothing to check · the check fails → stays Working, with the finding · 12 turns or 3 failed checks → Waiting · Pause → Queued
Waiting stopped on a question, a stall, a failed turn or three failed checks see above your answer or message → Working · Done · Back to the queue
Review finished, with nothing to check — yours to judge the agent said finished and the task has no Done when lines Done · your message → Working
Done checked, or you said so the check passed, or the Done button your message → Working

A task with Done when lines is done when the check passes: you wrote the lines, and a fresh turn found every one holds. Review is only for a task with nothing to check. Only the agent asks for Review. The app moves the rest. Dropping exists only before work has started — on a proposal, or on a queued task with no chat.

The agent never checks its own work. When it says it is finished, a fresh chat that has not seen the work reads the "Done when" lines and the folder — running whatever a line needs run — and answers each line with pass or fail. The result appears as a card in the task's chat, and the bar's Check tab opens the checker's own chat, read-only. A pass marks the task Done; a fail sends it back with the finding, and the next turn carries it; the third fail stops it and asks you. A task with no Done when lines has nothing to check and goes to Review, for you to judge.

Nothing waits for a clock. Every event that leaves work to do fires the next step at once: a turn ends and the task is still being worked, so the next turn goes; a check fails, so the fix goes; you press Done, Accept or Resume, so the next queued task is taken, or a plan is made when the queue is empty. Each step does one thing: continue the task being worked, take the next queued one, plan, or nothing. Each nudge sent into a task's chat is a turn. Turn 1 is the task's text; every later one is the same line, "Turn N of 12 — carry on with the task. Say in one line what the next step is", with the check's findings appended when the last check failed. A hidden note on every turn tells the agent the rules: do the next concrete piece, ask one concrete question and stop when it needs you, set review when every Done when line holds, change nothing else in the file. Twelve is a ceiling, not a count to reach — the nudges stop the moment the agent sets review or asks you, which can be turn 1. A task still Working after 12 stops and waits for you, and a message from you starts the count over, which the bar shows as "on your message" while that turn runs. A minute tick is the safety net for what no event covers — the app restarted, a shift beginning (all day, or only the day shift 08:00–18:00 or the night shift 22:00–06:00) — and where the subscription is measured. The Autopilot page's AUTOPILOT line says On (with the shift as a small card when there is one), Off shift, Paused, or Capped with the one reason: the plan's window is spent, the app is at its turn cap, or the subscription is above 75 %, which pauses the heartbeat for an hour. Heartbeat work always runs on the agent's own subscription and never borrows another.

You come first. Writing into any chat of the agent stops an Autopilot turn in progress — a task, a check, a plan — and your message goes the moment it lands; the task stays Working and the next beat carries it on after your turn. Autopilot never takes the agent's turn while a message of yours is waiting for it.

Pause, on the right of that line, stops the whole thing — no turns, no checks, no plans — until you press Resume. The page and the list stay open: you can read, edit, add and accept while it is paused, and the heartbeat carries on from there.

Planning runs when the queue is empty and no proposal is waiting for your decision, and keeps at most 5 tasks open. A task stopped for a word from you, or one in review, does not hold it back. A plan that finds nothing to do is not tried again for four hours.

How a goal ends. Two kinds of goal. One can be met: under the goal, a ## Done when list, like a task's, and a fresh check reads those lines against the folder as the first step of every planning session. Every line holds and the goal is met: no plan, planning stops, you are told, and the shift icon goes grey until you edit the goal. A line fails and the plan runs with what failed as its brief. One never ends — grow the subscriber list — and gets planning sessions per day instead: 1, 2 or 4, each a plan of at most 5 tasks, after which the page says "Planned for today · next 00:00" and what is queued still runs to the end. A goal can have both. Plan now is yours and never counts. A goal with neither has no brake, and the Autopilot tab says so in amber. The GOAL block on the page shows the Done when lines with the last check's verdict on each. The PLANNING line says when the next plan comes and why not sooner: "Next when the queue is empty", "Next when you decide · 2 proposed", "Next when a task finishes · 5 open", "Next in 3 h · the last plan found nothing to do", "Planning now". Plan now at its end runs one on demand. The Tasks | Plans switch at the top right of the Autopilot page shows the plans instead of the tasks: one row per planning chat with what set it off, how many it proposed, how many you accepted and dropped, and when. A row opens that chat; "Autopilot ›" in its bar comes back.

Where tasks show.

The Autopilot tab: the switch, the goal and its Done when (.skynet/goal.md, the lines under ## Done when, with the same @ and / menus as the prompt), planning sessions per day, when it runs (All day · Day shift · Night shift), and the mode when the queue is empty: Stop goes quiet until you add or accept a task; Pursue goal — plan, wait for approval runs a planning chat that proposes tasks for you to accept; Pursue goal — plan and execute, no approval starts them on its own, never more than 5 open.

Links

The toolbar's link chips come from .skynet/links.md — every [title](url) in it, in the order written:

[staging](https://staging.example.com)
[board](https://trello.com/b/abc)
browser: system

browser: system opens them in your own browser; the default is the shared browser (Brave). Right-click a chip to open it in the other one, once.

With no links.md, a folder with .skynet/box.yml gets its development box's addresses instead — its public ngrok names (https://<name>.ngrok.dev, https://<name>-api.ngrok.dev, …) when the file has an ngrok: line, otherwise its .localhost ones.

Sources — the @ menu

Every file in ~/Skynet/sources/ is one source in the @ menu, shared by all agents:

---
name: jira
detail: open tickets
min: 2
insert: [jira:{key}]
run: ~/.claude/skills/jira/jira search "$QUERY" --json
---
Notes for whoever opens this file.
Key Meaning
name: what you type after @
detail: the grey text beside it in the menu
min: characters to wait for before searching (default 2)
run: a command that prints [{"id": …, "label": …}] — title or name also count as the label
insert: what a picked row writes into the message; every {key} is filled from the row
ref: the reference word(s) this source owns, e.g. notion notiondb
resolve: a command that prints a reference's title, for its card
open: what clicking the card runs
match: a regex for references that are not in brackets; the first capture group is the body
icon:, tint:, subtitle: how its cards look (an SF Symbol; red, orange, yellow, green, blue, purple, pink, teal)

What you type reaches the command as $QUERY, and a reference as $REF — in the environment, never pasted into the command, so nothing needs escaping. A source whose command is a path that doesn't exist on this Mac is left out of the menu. A file with only ref: is a resolver: it draws cards but never appears in the menu.

Check them all at once from Terminal:

/Applications/Skynet.app/Contents/MacOS/skynet-mac --sources "roadmap"

References and cards

Anything in a reply that a source claims — [notion:…], [bear:…], [channel:…] — becomes a card with its real title. So do absolute file paths that exist, and plain web addresses. A file an agent writes in the turn gets a card too. Click to open; right-click for Quick Look, Show in Finder, Copy reference.


Background work and notifications

A claude turn can leave work running — background commands, subagents, schedules. The chat shows a hollow ring and the task chip; when the work finishes, the chat wakes by itself and you get a notification.

Quitting ends that running work — and anything an agent started and left running, such as a server — and it is not restarted on the next launch — so while any agent has a turn or background work running, ⌘Q asks first. Keep Working is the default; Quit Anyway quits. Your chats are not lost: every one is on disk and back in the chat list on the next launch, ready to continue — only the work that was still running is gone. A script can skip the question with tell application id "dev.hannisdal.skynet-mac" to quit saving no.

Notifications come when an automation starts, finishes or fails; when an agent asks you something while you are elsewhere; when a task needs you, is ready to review, is done or has stalled; when background work finishes; when a chat is parked on a plan limit or gives up retrying; and when a new version of Skynet is out. Clicking one opens the chat.

Quitting Skynet ends every session and everything running in them.


Activity

⌘S. One table, a row per agent that has anything at all: a turn running, tasks on its Autopilot, or automations on its clock. Running rows first, then what waits on you, then whose clock fires soonest.

Dashboard

⌘0. Panels are defined in ~/Skynet/dashboard/dashboard.json:

{"panels": [
  {"id": "clock", "title": "Clock", "run": "bun panels/clock.ts"},
  {"id": "notes", "title": "Notes", "file": "notes.html"}
]}

run: is a command that prints HTML (cached, refreshed with ↻ or Update all); file: is an HTML file in the dashboard folder. Optional: heavy (left out of Update all), timeout (seconds, default 30), js (allow JavaScript), owner (an agent's name, shown as a badge). A link to ?k=v in a panel re-runs its command with that in QUERY_STRING.

Telegram

Your agents, from Telegram on a phone. What you write to your own bot goes to an agent as a message; its answer comes back while it is being written, its questions arrive as buttons, and files it names in a reply are sent as files. The agent runs on this Mac in its own folder, on its own engine — claude, codex or pi — and the chat is in its chat list like any other.

Set it up on the Telegram page (⌘T, or the sidebar):

  1. In Telegram, open @BotFather, send /newbot, and give the bot a name and a username ending in bot.
  2. Paste the token BotFather answers with, and press Connect.
  3. Skynet shows a six-digit code. Send it to your bot. From then on the bot answers you and nobody else.
In Telegram What it does
/agents Pick the agent to talk to — favourites first. /agent name does the same by name.
/panels A Dashboard panel as a PDF — /panel name does the same by name. A panel that has a command is run first, as ↻ runs it, so what arrives is current; a panel that is a file is sent as its agent last wrote it. It is one long page, laid out at a phone's width or as wide as its tables need, with text you can select and links you can follow. A panel too wide or too long to fit says so in its caption. If the run fails you get the reason and the last page that worked.
/new A fresh chat with that agent. Without it, you carry on in the same chat, also after Skynet restarts.
/stop Stops the turn in flight. So does the stop button under a reply being written.
/status Which agent, and whether it is working, waiting for you, or idle.
anything else Goes to the agent — a /skill included. Photos and files are handed to it, up to 20 MB each. A location you share arrives as its coordinates, with the place's name and address when it has one; a contact as its name and number.

A question can be answered by its button or by writing the answer; writing back to a permission question is a no, with your reason. An answer from an agent other than the one you are talking to starts with that agent's name. Files go to the phone up to 50 MB.

Keep this Mac awake, on the Telegram page, stops the Mac going to sleep while Telegram is on — a sleeping Mac answers nobody. A message that reaches a Mac which is asleep anyway — on battery, or with the lid closed — is kept, and the phone is told so: the agent starts on it once the Mac has been awake for three minutes. It holds only on the power adapter, never on battery; the display still turns off; and closing the lid still puts the Mac to sleep, unless an external display is connected.

Telegram's servers see what is sent. Leave it off for anything that must not leave the Mac. It works while Skynet is open; what you send while it is closed waits at Telegram for a day. Pair another phone forgets yours and shows a new code; Disconnect removes the token.

Search

⌘F searches what was said in every chat of every agent — claude, codex and pi — plus the archive in ~/Skynet/chatlogs/. Press ⏎. Every word has to appear in the same chat; tool output and pasted files are not searched. Up to 200 hits, newest first. ⌘K searches only the agent you are in.


Updates and versions

Versions read R12-2026-09-10: the release number, one more each time, and the day it went out. A copy built from source says R12-dev. About Skynet shows yours.

Skynet checks the website once a day. When there is a newer release it asks you once, in a dialog (the Dock icon bounces if Skynet is in the background); Later means not again for that release; Check for Updates… in the Skynet menu asks now. Install and Relaunch downloads it, checks that it is signed by H5 Innovations, replaces the app and opens it again — after warning you if any chats are working, since quitting stops them. If anything fails, the app you have stays as it was and the website is one click away. Copies built from source never check on their own.

The website counts that daily check, each download and each update, by build number and nothing else — no address and no identifier of your Mac is kept. That is how the people who make Skynet know how many copies are in use.

Feedback

Help → Send Feedback…, or Send Feedback… beside the search at the top of this guide, opens a box for a bug, something confusing, or something you wish Skynet did, with an optional email if you would like an answer. It goes to the people who make Skynet together with your Skynet and macOS versions — nothing else: no chat, no file, no agent name.

An agent can send it for you too. Skynet keeps a skill, skynet-feedback, in ~/.claude/skills/ — every engine sees it — so "tell the Skynet developers the chat list jumps when…" in any chat works: the agent shows you the text and sends it when you say so. The skill runs skynet-mac --feedback "<text>", and Skynet writes it again at every launch, so an edit to it does not last.

The download on the website is a disk image: open it and drag Skynet onto Applications. It is signed and notarized by Apple.

Files in ~/Skynet

Path What it is
SKYNET.md the prompt every agent shares
GUIDE.md this guide
agents.json the agents in the sidebar
favourites.json, agent-sort favourites and the sidebar's order
context/ shared context files
sources/ the @ menu's sources
dashboard/ Dashboard panels
accounts/ extra Claude accounts
telegram.json the Telegram bot's token, the phone it is paired with, and each agent's chat with it — readable by you only
chatlogs/ archived chats from earlier systems
quotes.csv your own greeting quotes (Number;Quote;Author), instead of the built-in ones
pinned-chats.json, unread-chats.json, chat-names.json pins, unread dots, and chats you have renamed
adopted-chats.json runs you have written into, which the chat list therefore shows
chat-models.json the model each chat runs on, by session id — set at its first turn, changed only from that chat's model chip
parked-chats.json chats waiting for a plan to reset
heartbeat-state.json per agent: when Autopilot last beat, what it did, when the last empty plan was, and a usage pause if one is on

From the terminal

The app's binary answers a few questions without opening a window:

S=/Applications/Skynet.app/Contents/MacOS/skynet-mac
$S --links          # every agent's link chips and where they open
$S --sources "q"    # run every @ source once and show what came back
$S --quickstarts    # every agent's quickstarts
$S --automations    # every agent's automations, their schedule and state
$S --tasks          # every agent's tasks, their status and chat, and the last heartbeat