中文 · README · Feature tour
Each answer says what you see, why, and what to do.
- Codex (or another full-screen program): I can't scroll back through the conversation
- An agent's pane never takes its messages; they stay queued
- A pane stays busy and nothing is delivered
- How do I change a pane's work mode?
- I swapped two panes: where do messages go now?
- A message from another machine is refused by a shell pane
- The phone can't open the page
- Tell me on my phone when a job finishes, even when it is locked
- The Feishu or DingTalk bot refuses keepane's messages
- Windows: a hook with a quoted keepane path fails
- macOS: "Operation not permitted" in some folders
What you see. In a pane running Claude Code you can scroll up (C-b [, the
phone, C-b / for the day's history) and read the whole conversation. In a
pane running Codex, what went by is gone.
Why. Codex draws in the terminal's alternate screen, like vim or htop: a screen of its own that it redraws in place, so nothing ever scrolls off into the terminal's history. keepane, like tmux and every terminal, keeps history only from the normal screen. Claude Code prints its conversation down the normal screen, so its lines scroll into history.
What to do. Run Codex on the normal screen:
codex --no-alt-screenor for good, in ~/.codex/config.toml:
[tui]
alternate_screen = "never"(Codex's default, auto, turns the alternate screen off only inside Zellij.)
Without changing anything, Ctrl+T in Codex opens its own transcript.
Codex's issue tracker has reports that on the normal screen it still redraws
the whole screen now and then, which leaves repeated lines in the history
(seen in Zellij and the VS Code terminal). If the history looks muddled,
that is Codex's redrawing; its transcript (Ctrl+T) is the clean record.
The same holds for any full-screen program: keepane cannot keep what the
program never lets scroll.
What you see. send-message to a pane in ai work mode says queued ... (ai, busy, ...), and the message never arrives; the dashboard or the
phone shows it waiting. It looks as if the agent forgets to check its inbox.
Why. An agent does not read its inbox itself. At the end of each turn
its hook runs keepane pane-ready, and keepane types the next message in as
its prompt. For Claude Code, Codex and pi keepane also reads the agent's
transcript, and frees the pane about 3 seconds at the most after a turn there is over;
any other agent without that hook never counts as free. keepane says so:
the reply to send-message gets a second line, %N has not said it is free since its agent started ..., and the dashboard and the phone mark the pane.
What to do.
keepane setup # each agent: on this machine? hook? MCP server?
keepane setup codex --install # or claude, gemini, cursor, opencodeEvery file is backed up first and only keepane's entries are added. Then
start the agent again in the pane. Codex runs a new hook only once you trust
it: in Codex, /hooks, and trust keepane's two. Another agent works if it
can run a command at the end of each turn: have it run keepane pane-ready -q there.
What you see. The pane's agent or shell is plainly waiting, but keepane
does not count it as free (#{pane_state} reads typing or busy).
Why. Typing into a pane holds its messages until its next signal (the
shell's prompt, the agent's hook or, for Claude Code, Codex and pi, a turn
over in its transcript), so a message never lands in the middle of a line
being typed: keys with no Enter read typing. Text typed and then deleted,
or a prompt that was not redrawn, can leave it waiting for a signal that
does not come. An ai pane whose agent has exited reads no-agent, and
waits for an agent to be started there.
What to do. From outside the pane (another terminal, or the C-b :
prompt):
keepane pane-ready -t %agentIn that pane, run keepane set-work-mode ai (or shell, or normal). From
outside keepane (a terminal, the C-b : prompt, a key) you can name the
pane: keepane set-work-mode -t %builder shell. A command run in one pane
cannot change another pane's mode, so nothing in one pane can turn another
into a shell that runs what it is sent.
A pane's id (%7) and name (%builder) go with the pane, wherever it is
moved or swapped (C-b {, C-b }, swap-pane). A message to %7 or
%builder reaches the same pane as before. A position (work:0.1) names
whatever pane is there now. A full address ($1:@2.%7) also says where the
pane is: if the pane has moved to another window, the delivery is refused
rather than sent to the wrong place.
Why. What comes from a paired machine goes only to ai and normal
panes. A shell pane would run it as a command, so that is off until you allow
it for that machine.
What to do. On the receiving machine, in a terminal outside keepane (not in a pane, so an agent cannot grant it to itself):
keepane link allow 192.168.1.20:7681 --shell--screen lets that machine read a pane's screen (keepane link capture);
--panes lets it start panes here; --push lets it send commits into
repositories here (keepane clone, keepane push).
- The phone and the computer must be on the same network, or both on
Tailscale.
keepane web statusshows the address being served and who is connected. - Windows asks the first time whether keepane may use the network: allow it for private networks.
- The code changes each time
keepane webstarts (unless--keep-key): scan the new one. - It is plain HTTP, fine at home; from outside, go through Tailscale or a similar private network, not a port opened to the internet.
- Its time was up (24 hours unless
--forsaid), it was stopped, or it was--onceand went once.keepane sharelists what is still shared. - Shares last only as long as the server: after
restart-serveror a reboot, share it again. - The link is on the phone page's port: after
keepane web stopnone of them answers;keepane webserves them again (on its new port, if it changed:keepane sharelists the links as they are now).
The phone's page tells you (a banner, a sound, a buzz on Android) while it is open. A locked phone stops its pages, and a page on plain HTTP cannot raise a system notification, so for a locked phone let keepane post to a service that has an app:
- ntfy (free, open source, iOS and Android; or your own server):
install the app, subscribe to a topic of your own (anyone who knows a
topic's name on ntfy.sh can read it: pick one hard to guess, or run your
own server), and
set -g done-webhook https://ntfy.sh/<your-topic> set -g done-webhook-format text
- A chat you already use: Feishu, WeCom, DingTalk, Slack or Discord. Add
an incoming-webhook bot to a group, then
set -g done-webhook <the bot's address> set -g done-webhook-format feishu # or wecom, dingtalk, slack, discord
- Anything else: the
pane-donehook runs a command of yours with the details inKEEPANE_DONE_*variables (see the README).
What counts is done-events (command agent by default: a command that ran
done-after seconds, 30 by default, and an agent's turn), for panes with a
name or in ai/shell mode (done-panes all for every pane). Put the
lines in your config file to keep them.
show-messages says done-webhook: refused (...) with what the chat
answered. A bot's security setting decides:
- Keywords: every message keepane sends a chat starts with
keepane; addkeepaneas the bot's keyword. - Signature (Feishu's "signature verification", DingTalk's "sign"): keepane does not sign; turn it off, or use keywords or an IP allow list instead.
- IP allow list: the address the computer reaches the internet from must be on it.
An agent on Windows may run its hooks in PowerShell, where a quoted path
followed by arguments is a syntax error. Write the program unquoted
(keepane pane-ready -q, with keepane on the PATH), or with the call
operator: & "C:\path\keepane.exe" pane-ready -q. keepane setup writes the
unquoted form.
What you see. ls in Documents, Desktop, Downloads or another protected
folder says Operation not permitted, sometimes only after reconnecting.
Why. macOS privacy protection (TCC) decides per terminal application
which folders its programs may read. keepane's server and every pane inherit
the permission of the terminal that started them. If the same ls fails in
iTerm2 or Terminal outside keepane too, keepane is not involved.
What to do. System Settings → Privacy & Security → Full Disk Access (or
Files and Folders): turn it on for your terminal application, then quit and
reopen that application. A keepane server started before the change may
still run with the old permission: keepane kill-server, start it again
from the terminal, and keepane resume brings the sessions back (their
layout and directories; the programs in them start afresh).