lwis docs

Agents / Claude Code

Claude Code

The lwis plugin delivers your captures into the Claude Code sessions you choose. It ships inside the lwis binary, stays inert until you attach a session, and never relays tool approvals from a device.

Set up the plugin

lwis setup claude                # install the plugin for every project, start lwisd once
lwis install-service --enable    # keep lwisd running across logins
lwis pair --label laptop         # pair your phone or browser, if you haven't yet

lwis setup claude writes the plugin as a local marketplace (lwis-local) under ~/.local/share/lwis/claude and installs lwis@lwis-local at user scope. Its hooks and MCP server call this lwis binary by absolute path with the daemon's runtime directory, so PATH and XDG_RUNTIME_DIR don't matter inside Claude Code.

FlagEffect
--channelsPrefer channels over the session inbox. Only useful where your organisation enables channels; start Claude with claude --channels plugin:lwis@lwis-local.
--no-installOnly write the plugin files; load them with claude --plugin-dir <dir>.
--claude <path>The claude executable to use (default: from PATH).
--removeUninstall the plugin and delete its files.

Plugins load when a session starts. Exit sessions that were already running, then claude --continue reopens the same conversation.

The hooks never start lwisd. If the daemon isn't running, the plugin's tools answer "lwisd not running" and the hooks stay silent. Run it as a service, or by hand with lwis up (lwis up --idle-exit 60 exits after an hour with nothing attached).

After an update, the next session start asks a running lwisd to re-exec itself from the updated binary (only the same file, only a newer version; logged in lwis log).

Attach a session

A new session is not reachable: your devices don't list it, and captures addressed to it are refused. Once per project, the session start shows "lwis: this session isn't attached; /lwis:on to receive captures".

CommandEffect
/lwis:onAttach this session. Captures arrive on your next prompt, with a desktop notification.
/lwis:on --wakeAlso let a capture start a turn while the session is idle.
/lwis:on --allow-repliesSend lwis_reply without asking you each time.
/lwis:offDetach. Waiting captures and replies are dropped.
lwis allow <dir>Attach every session started in that directory or below (--wake, --allow-replies accepted).
lwis disallow <dir>, lwis allowedRemove a directory, list the allowlist.
lwis attach [sid], lwis detach [sid]The same from a terminal, by session id.
LWIS_ATTACH=1 claudeAttach from the start (LWIS_ATTACH=wake also wakes).

An explicit /lwis:on or /lwis:off is remembered per Claude session for 30 days (it follows /clear and /resume), and an explicit detach beats the allowlist. lwis sessions lists every session lwisd knows, attached or not.

The slash commands carry disable-model-invocation, so Claude doesn't run them by itself. An agent allowed to run shell commands without asking could still run lwis directly: your permission prompts are that gate.

How captures reach a session

lwisd picks a delivery path ("rung") per capture and per attached session. lwis doctor shows which one each session is on, and why.

RungHowStarts a turn when idle?
R0Channel notification: the first choice with "ladder_channels": "prefer" (set by lwis setup claude --channels), and the fallback for --wake sessions without a usable inbox socket (R2 as backup)Yes, where channels are enabled
R1The session's own inbox socket (Claude Code 2.1.224 or later), only for sessions attached with --wakeYes
R2The UserPromptSubmit hook adds the capture to your next prompt. The default.No
R3A desktop notification and the statusline segmentNo, you act

Inside Claude, the plugin provides four tools: lwis_get_capture (view a capture's images, gestures and page targets), lwis_list_captures (captures still available to this session, for up to 24 hours or until the session ends), lwis_reply (a plain-text reply to the device, at most 1000 characters; to an agent pairing's report, up to 8000 and one file) and lwis_request_capture (ask you to take a capture on a paired device).

Held captures and strict mode

Some sessions only get a stub instead of the capture. Claude can view it after you accept it:

/lwis:accept c_…

Captures are held when:

For a capture from a confirm device, lwis accept <cid> in a terminal also works: the capture is then delivered to its session through the usual rung.

Reply approval

When Claude calls lwis_reply, lwisd keeps the reply until you approve it, and shows a desktop notification.

  1. Review the waiting replies in a terminal, not through Claude:

    lwis replies
    

    It prints each reply's id (ra_…), project, recipient and text. Ids are never shown inside Claude, so the model can't approve its own replies.

  2. Send one with /lwis:approve-reply <id> in the session, or lwis reply-approve <id> in a terminal.

  3. Drop one with lwis reply-deny <id>.

A reply nobody approves expires after 1 hour; lwis log records it as reply_expired.

/lwis:approve-reply without an id only says how many replies wait. Attach with --allow-replies to skip approval for a session.

Statusline

lwis statusline prints a segment for your status line. Compose it into your own command rather than replacing it:

"statusLine": {"type": "command", "command": "input=$(cat); echo \"$(echo \"$input\" | your-statusline) $(echo \"$input\" | lwis statusline)\""}
SegmentMeaning
📷 lwisThis session is attached (nothing is printed for an unattached one while lwisd runs).
📷 lwis 2Two captures wait for your next prompt.
📷 lwis 1⏸One capture waits for /lwis:accept.
📷 lwis ✉1One reply waits for your approval.
📷 lwis pausedDelivery is paused (lwis resume).
📷 lwisd offThe daemon isn't running.

Audit log and pause

Troubleshooting

Start with:

lwis doctor      # dirs, lwisd, pairings, service, browsers, and each session's rung
lwis sessions    # attached or not, strict or held, waiting replies
SymptomFix
/mcp shows the lwis server with "tools fetch failed"Update to 0.8.2 or later (lwis self-update), then restart the session. Earlier versions failed Claude Code's newer MCP handshake.
Tools answer "lwisd not running"lwis up, or lwis install-service --enable.
Your devices don't list the sessionAttach it: /lwis:on, or lwis allow <dir>.
Captures only arrive when you typeThat's the default. Attach with /lwis:on --wake to wake idle sessions.
doctor says "inbox socket: not registered"Claude Code older than 2.1.224, bare mode, a container boundary, or the SessionStart hook didn't run. R2 still works.
doctor says lwisd runs inside a Claude Code process treeRestart it outside Claude: lwis down, then lwis install-service or lwis up. R1 is refused until then.
The session doesn't have the pluginIt started before lwis setup claude: exit and run claude --continue.
XDG_RUNTIME_DIR is not set (a root shell, a container)Create it as the message says: mkdir -p -m 700 /run/user/$(id -u) && export XDG_RUNTIME_DIR=/run/user/$(id -u).