For AI agents: a documentation index is available at https://www.plungeai.com/docs/llms.txt. Append .md to any page URL, or send Accept: text/markdown, to get markdown. Setup instructions for agents are at https://www.plungeai.com/docs/agents.md. One ozk_ key opens every plane, models included.

Documentation Index: fetch the complete documentation index at /llms.txt. Use this file to discover all available pages before exploring further.

Slack Remote lets you follow and drive your sessions from one Slack channel, from your phone or anywhere else. When a session waits for you, finishes or is blocked, the engine posts it in the channel, and you answer with a button or a reply in the message's thread. The engine dials out to Slack over Socket Mode, so the Mac needs no open port and no relay.

What is posted

One top-level message per event, so each one reaches your phone as a notification. Every message starts with #<code> · <title> · <folder>: the session's short code, its title and its folder. Nothing is posted while a turn works.

EventMessage
A permission askThe permission and its patterns, with the buttons Allow once, Always and Deny.
A questionThe question and its numbered options. One question with one to five options, one choice and no typed answer gets a button per option; any other ends with Reply in this thread.
DoneDone — and the first line of the answer, when a session's turn finishes.
BlockedBlocked — and the reason, when a turn stops on an error, a refusal or a bound.

An ask raised by a sub-agent is posted for its root session; a sub-agent's finished turn posts nothing. Once an ask is answered, in Slack or in the window, its message loses its buttons and gains a line saying how it ended: Allowed once from Slack, Denied, Answered: <text>, Expired after 30 min or No longer open.

Answering from Slack

Press a button, or reply in the message's thread:

Reply in the threadOn a permission askOn a questionWith no open ask
yes, y, allow, okAllow onceThe answerThe next prompt
alwaysAlways allowThe answerThe next prompt
no, n, deny, rejectDenyThe answerThe next prompt
stopInterrupts the sessionInterruptsInterrupts
Any other textDeny, with the text as the correctionThe answerThe next prompt

Case and a trailing . or ! do not matter (Yes. is yes), and a leading mention of the bot is dropped. A reply in an ask's thread is for that ask only: once the ask is closed, the reply is the next prompt. A reply in a Done or Blocked thread answers the session's oldest open permission ask, else its oldest open question, or is the next prompt when it has neither. Top-level messages in the channel, edits and other bots' messages are ignored: a prompt always goes to a session through one of its threads. A prompt from Slack shows in the window that has the session open (Ocean pager, Xcode), then its reply, as if typed there.

Several windows and Macs

Every window that hosts the engine connects: plain oceancode (the pager), oceancode acp and oceancode serve. One-shot oceancode run, goal and workflow never connect. Slack allows ten connections per app; a window past that keeps retrying. Automation that launches oceancode acp or serve unattended sets OC_SLACK=0 (Ocean Factory, Ocean Vibe and the Ocean app do), so it never takes a press or a reply meant for your windows.

Slack hands each button press or reply to one of the app's connections, whichever window that is. On one Mac that does not matter: the window that receives it hands it to the window that owns the session, through peers.db, within about two seconds. A window cannot hand a reply to another Mac, so a reply that lands on the wrong Mac is dropped. On several Macs, give each Mac its own Slack app; the apps can share one channel. Name each app after its Mac, so its posts and its /invite are told apart: change display_information.name and features.bot_user.display_name in the manifest, for example to Ocean Code – Studio. Each Mac's connected message also names its hostname.

Setting it up

  1. At api.slack.com/apps (opens in a new tab), choose Create New App → From an app manifest, pick your workspace and paste the manifest.

  2. Choose Install to Workspace, then copy the Bot User OAuth Token (xoxb-…) from OAuth & Permissions.

  3. In Basic Information → App-Level Tokens, generate a token with the scope connections:write and copy it (xapp-…).

  4. Create a private channel and invite the bot by its name: /invite @Ocean Code with the manifest as it is, or the name you gave the app. It must be private: whoever can write in the channel can run prompts on this Mac, and connect refuses a public channel.

  5. Copy the channel's id: open the channel's details; the id (C…, or G… for an older private channel) is at the bottom.

  6. Connect:

    oceancode slack connect --channel C0123456789

    It reads SLACK_BOT_TOKEN and SLACK_APP_TOKEN from the environment, else two lines piped on stdin (the bot token, then the app-level token), else asks for both in the terminal (what you paste shows on screen). It checks the bot token, that the channel is private, then the app-level token and Socket Mode, posts Ocean Code connected from <hostname> (this Mac's hostname) in the channel, and only then stores them and prints SLACK_CONNECT_OK team=<team> channel=<id>.

  7. Open a new window, or restart the open ones: a window reads the tokens when it starts.

oceancode slack status shows the team, the bot user, the channel and whether OC_SLACK leaves the bridge on. connect again without --channel replaces the tokens and keeps the channel; oceancode slack disconnect removes them. Flags and exit codes: 21 · CLI reference. Ocean pager has no Slack view; status is the surface.

The manifest

display_information:
  name: Ocean Code
features:
  bot_user:
    display_name: Ocean Code
    always_online: true
oauth_config:
  scopes:
    bot:
      - chat:write
      - groups:history
      - groups:read
      - channels:history
      - channels:read
settings:
  event_subscriptions:
    bot_events:
      - message.groups
      - message.channels
  interactivity:
    is_enabled: true
  socket_mode_enabled: true

chat:write posts and updates the messages, and always_online shows the bot as present. The groups: scopes read a private channel and the channels: scopes a public one (the two :read scopes also let connect tell which the channel is); the two events deliver thread replies, interactivity delivers button presses, and Socket Mode carries both over the connection the engine opens, so the app needs no request URL. The app-level token's scope, connections:write, is chosen when you generate the token (step 3); a manifest cannot carry it.

Privacy

Slack, and everyone in the channel, sees: session titles, folder names, the permissions asked and their patterns (commands, paths), question text and options, the first line of each answer, and why a turn was blocked. What you type in a thread goes to the engine and, as a prompt, to the model. Anyone in the channel can press a button or reply with the same power as you at the keyboard, so connect refuses a public channel; keep the private one to you and the bot. Each press and reply the engine carries out is logged with the sender's Slack user id (never the text).

The two tokens and the channel id are in the data dir's auth.json (mode 0600), under slack. No command prints a token and no log line carries one.

Turning it off

OC_SLACK=0 in a window's environment keeps that window off Slack (02 · Configuration); oceancode slack disconnect turns it off for every window started afterwards. The webhook recipe in 10 · Hooks is the one-way alternative: it posts, but you cannot answer.

Troubleshooting

ErrorCauseFix
not_in_channelThe bot is not in the channel./invite @<your bot> in the channel, then connect again.
channel_not_foundA wrong id, or a private channel the bot is not in.Check the id (step 5) and invite the bot.
is a public channelThe channel is public: everyone in the workspace could run prompts on this Mac.Create a private channel (step 4), invite the bot and connect with its id.
invalid_authA wrong bot token, or the app was uninstalled.Copy the Bot User OAuth Token again (reinstall first if needed).
missing_scopeThe app lacks a scope from the manifest.Paste the manifest again, reinstall, and connect with the new bot token.
Socket Mode refused the app tokenA wrong app-level token, one without connections:write, or Socket Mode off.Generate the token again (step 3); check socket_mode_enabled.
set both SLACK_BOT_TOKEN and SLACK_APP_TOKEN, only one token on stdinOnly one of the two tokens was given.Give both: the two variables, or two piped lines (the bot token first).

A window that loses Slack reconnects on its own; a refused token stops its bridge until the next start. Its slack: log lines name the bot, the channel and Slack's error (18 · Operations).

Planned: TI-34

The docs assistant is not available yet. You can hand these docs to your own assistant instead.