Skynet guide
Every screen, shortcut, right-click menu and setting — the same guide ⌘? opens in the app.
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.
Sidebar
| 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
- Search this agent — press ⏎ to search the titles and the text of every chat in this agent. A match shows the line it was found in.
- New chat — clicking it again reuses an empty chat rather than making another. If you started writing in a new chat and then opened a different one, New chat takes you back to that unsent message.
- Chats are grouped Pinned, Today, Yesterday, This week, Earlier. Right-click a chat to Pin to top or Unpin.
- Rename… on the same right-click gives a chat whatever name you like, instead of the one its engine made up. The name is Skynet's own — the chat itself is not touched — and clearing the field — or Reset, once a chat has a name of yours — gives the engine's title back. It is the only way to name a codex chat, which is otherwise always called whatever you said first.
- Each row shows the engine's logo, a clock if an automation made it, a paper plane if you have written into it from Telegram, and the same marks as the sidebar.
- A chat that has never run but holds queued messages sits at the top with a clock and "queued".
- Autopilot, above Pinned, for an agent with it switched on (Agent Settings → Autopilot). Only tasks waiting for you, ready to review, or being worked; a line under them counts the rest. The header opens the agent's Autopilot page. See Autopilot.
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:
- Tool calls fold into one line, "N tool calls · time"; click to open them. Errors never fold.
- Cards stand in for files, links and references — click to open. An
.htmlor.svgfile opens in a window of its own inside Skynet, with its styles and images. - Questions, permission requests and plans appear as cards to answer: Answer, Allow / Always allow / Deny, Approve / Revise.
- Above the message box, outside the scrolling chat, sit the working dots while a turn runs and the task chip. The task chip shows background work — subagents, background commands, schedules — that outlived the reply. Under it, one row per task: what it is, and for a subagent the tool it last used, its step count and how long ago its last step was. A subagent whose last step keeps getting older is probably stuck. Stop on a row stops that task alone; the chat and its other tasks keep going (claude only). The chip's ■ ends the chat's whole session and everything running in it.
- latest ↓ appears when you have scrolled up while the agent is writing; it jumps back to the end.
- Drop a file, a folder or an export (Photos, Preview) anywhere on the chat to attach it. Exports are saved into the agent's
.skynet/files/. - ⌘V in the message box attaches too: files copied in Finder, and a copied image — a screenshot taken to the clipboard, "Copy Image" in a browser — which is saved into
.skynet/files/asPasted image <date>.png. Copied text that happens to carry a picture beside it (Word, Notes, a web page) still pastes as text.
Message box
- Launching the app, switching agent, and starting or opening a chat — New chat, ⌘N, a click in the list, ⌘↑/⌘↓, a notification, a search hit — put the cursor here, ready to type.
- ↩︎ sends. ⌘↩︎ also sends. ⇧↩︎ starts a new line. While a turn is running in this agent, ↩︎ queues the message for when it finishes. One chat per agent runs at a time — unless the agent has Chats run in parallel on (Agent Settings → Engine), when only the chat that is itself running queues.
- / lists skills. @ pulls things in: files, any installed source (Notion, Bear, Slack…), a context, or another agent. Type after it to search:
@notion roadmap. - ↑ in an empty box brings back your last message in this chat; ↑ again goes further back, ↓ comes forward. Edit the text and the arrows move the caret again.
- Queued messages each have four buttons: ↑ sends into the turn running now, ↓ takes it back into the message box to edit (anything already typed there is kept, below it), ⏸ holds it until you decide, ✕ discards it.
- The paperclip attaches files; so does dropping them.
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:
- Brave — the shared browser, if the cobrowser skill is installed. Right-click to quit it.
- Plan status — the account badge and, beside it, three small columns: the 5-hour window, the week, and this model's own cap, left to right. They share one scale, so the tallest column is the one nearest its limit. Faint under 70 %, amber over 70, red over 90. Hover it for every number — each window's percentage, when it resets, and which account is paying. The badge turns amber with ↩︎ when it is borrowing another account because the chosen one is over 70 %.
- Zed (
</>), Terminal, Finder and person-with-gear — the agent's folder in each, and Agent Settings. - Link chips — the addresses in the agent's
.skynet/links.md, or its development box. See Links.
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:
~/Skynet/SKYNET.md— the prompt every agent shares. Edit it in App Settings → System prompt.- The agent's
CLAUDE.md. - 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
- printing something on stdout means there is something to do — what it printed goes into the prompt,
- printing nothing does nothing: no chat, no notification, no log,
- a non-zero exit means the check is broken — no turn, and the row's dot goes red with the reason.
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 chat list has three sections, a line between each: Automations, Autopilot (when it is on), then your chats — New chat, search, the list by day. An automation's runs and a task's chats are not in the list; they live under their section. A run you write into becomes one of your chats: from your first message it is listed with the rest, with a clock beside it to say an automation started it, and it stays under its automation too.
- Automations is the inbox for scheduled work: what is running or queued, and every run that finished while you were away, with an amber dot (ran) or a red dot (failed) until you open it. A run is one row for as long as it is open: while its turn has ended and background work is still out it stays Running, with the hollow ring and how long that work has been going, and becomes Ran when the work has reported. A broken check stays red until it is fixed. The row's clock is green when the agent has any automations and grey when it has none; it carries how many in a small pill; its amber count is the unseen runs, and its mark the worst of them. Click the row for the agent's Automations page — one row per automation with when it runs and its last run; click one for its runs, click a run for its chat, which carries an "Automations ›" bar back. Add is on the page.
- Autopilot holds only what waits for you, what is ready to review, what is being worked, and a planning run while it runs. Its icon is the shift — sun, moon or ∞, green on shift, amber paused, grey off shift — and after the label sits the mode when the queue runs empty. Its count is what waits on you — waiting, review, proposed — and its mark the worst of them. Task chats are not in the chat list at all — done ones included — the Autopilot page is where they are. A line under the section says so in amber when Autopilot is paused, off shift or capped. Its row opens the agent's Autopilot page; Add is on the page.
- The Autopilot page: the goal, the Autopilot line with Pause and the planning line with Plan now, then one table with a filter per status — glyph, name, from, status, check, when. It is for overview and navigation: a task with a chat opens its chat; a proposal or a queued task with no chat opens as a sheet with the task, its Done when, and Accept, Start now, Move to top or Drop.
- A task's chat carries a bar at the top: "Autopilot ›" when you came from the list, the name, three tabs — Task with the brief and its Done when lines, read-only, the facts — status, from, created, turns, check — a line for the state, and Open the file, so the text is one click away at every stage; Chat with the task's status; Check with the check's verdict (Pass · 3 of 3, Fail · 1 of 3, Checking) — and the actions: Pause while Working; Back to the queue and Done while Waiting; Done in Review; Move to top and Start now on a paused task. Under it, the turn count and when. The Check tab shows the checker's own chat, read-only; Chat brings you back. The message box's placeholder says what writing does in that state. Make this a task on any chat's right-click hands that conversation to the heartbeat.
- Add is two boxes: the task, and how to check it. The first line of the task is its name. A task that is only a name is still a whole task: the agent does what the name asks and decides what done looks like. A proposed or queued task opens the same two boxes, editable, as a sheet.
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.
- NOW — a pulse and how many things run; a hand and how many wait on you. Click it for the running chat.
- AUTOPILOT — the shift (sun for day, moon for night, ∞ for always; green while on shift and free to work, amber while paused or capped, grey off shift), the mode when its queue runs empty (nothing for Stop, a person-with-check for plans you approve, a bolt for plans that start on their own) and one bar of its open tasks, left to right queued, working, needs you, with the total. Click it for the Autopilot page.
- AUTOMATIONS — the count in a pill with the section's clock, the clock red when a last run failed or a check cannot run, amber when one is queued, green while one runs; then the next fire. Click it for the Automations page.
- Each cell is its own link, and says so: the one under the pointer greys like a button, and a cell with nothing in it stays flat. The agent's name opens the agent.
- The header is the app's turn cap — how many top-level turns run, of the 10 it runs at once — and each subscription drawn as the usage popover draws it: a thin column per window, the highest number beside them.
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):
- In Telegram, open @BotFather, send
/newbot, and give the bot a name and a username ending inbot. - Paste the token BotFather answers with, and press Connect.
- 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