npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@yu_robotics/remote-cli-router

v1.6.193

Published

Router server for remote CLI - message forwarding between Feishu and local clients

Readme

@yu_robotics/remote-cli-router

Router server for remote-cli — manages message forwarding between Feishu (Lark) and local CLI clients via WebSocket.

Backend executable discovery is local-client behavior. CLI 1.6.119 supplements Linux/macOS startup PATH and honors configured backend commands across detection and execution, preserving ZCode's native unset/empty-command lookup. Upgrade and restart the client to obtain this fix; upgrading only the Router does not repair an older client's environment. Valid client services need no reinstallation. The Router runtime, wire protocol, and existing compatibility requirements are unchanged. See Backend Executable Discovery.

Public Activity

From Router 1.6.158, completion pagination keeps the final body item (or complete worker group) with the completion note, optional model metadata and thread controls when they fit together. This avoids preventable footer-only continuations, including replies without model metadata. Indivisible oversized groups still split according to node, size and table limits; thread-button refreshes preserve the final body. This does not change streaming completion timing or the wire protocol.

From CLI 1.6.153, Codex shell calls no longer lose their label when native command actions are absent or unknown. Native reads, searches, and directory listings remain preferred. Other calls use fixed operation labels such as Run npm command or Run Git command for simple allowlisted programs, and Run shell command for compound or unrecognized commands. These are deterministic operation labels, not model-authored purpose summaries: installed Codex 0.160.0 command items have no per-call description field. Arguments, full paths, output, and execution-wide reasoning are never copied into these fallback labels. Late native action metadata can enrich a pending row before its first result; repeated results retain one row. Existing description fields, heading limits, and card-node counts are unchanged; upgrade the CLI, with no new Router capability required.

From Router 1.6.145, a foreground tool result updates its original collapsed tool row rather than adding a second disclosure. Input, output, and per-file diff previews remain inside; later text and worker slots stay stable. Unknown IDs and orphan results are not guessed into another call. Existing CLI peers are compatible, and worker cards and approvals are unchanged. See Code Change Previews.

From Router 1.6.146, Bash and other foreground tools share a compact heading with a gray success dot, pending hourglass, or gray failure cross, plus the tool name and an optional public description or file basename. Full tool IDs and explicit status labels remain in the expanded details. Raw commands are not fallback headings. Recursive card-node accounting and cross-page replacement continue to preserve activity tails and completion controls.

CLI and Router 1.6.147 prefer meaningful per-call descriptions or titles over file basenames, including ACP call/update titles and explicit AGY/Pi labels forwarded by the CLI. Redundant tool-name titles are omitted. Terminal-only titles never synthesize calls; results update status/output and preserve the existing label. Missing summaries are not generated from commands or execution-wide activity. Labels remain literal and bounded in the existing heading, without extra card nodes or a protocol-version change. Older clients keep input-label and basename fallbacks; older Routers ignore the new optional fields.

From Router 1.6.148, the status symbol is always a dot (•): green for success, blue while awaiting a result, and red for failure. This replaces the pending hourglass and failure cross without changing per-call labels, expanded status text, asynchronous in-place updates, or card-node counts. The color change alone does not require a CLI protocol update.

CLI and Router 1.6.144 negotiate optional activityProgress without a protocol version bump. One mutable status row sits at the tail of the newest active main card, after tools and workers, and moves when the reply paginates. Historical pages do not retain a live Running row. Each worker shows its own bounded activity below its identity. Input requests and final results win over progress; completion preserves the terminal status, model/effort note, and thread controls. Raw thinking is not displayed as activity and progress is not a percentage. Older clients keep their existing cards. See Public Activity.

Settings Cards

CLI and Router 1.6.152 negotiate settingsCards on protocol version 1. Bare /backend, /model, and /effort replace their command placeholder with a standalone interactive settings card. From Router 1.6.160, backend choices submit immediately using the selected scope, defaulting to Current thread, without Confirm. Scope buttons only change the next click's target; scope persists within the same card after backend acknowledgements and defaults to Current thread on reopening. Follow global submits immediately for the original thread and restores Current thread scope after acknowledgement. Model and effort buttons submit immediately, including an inactive target backend, without switching the coordinator. The CLI remains authoritative for native validation and persistence; the Router shows pending or unknown state until a matching result confirms application.

From 1.6.154, numbered headings, subtitles and dividers distinguish backend selection above application scope (Confirm removed in Router 1.6.160), or target backend, its model/effort choices and secondary actions. Explicit checks identify the acknowledged backend, selected scope and known preferences without guessing unknown values. Section elements participate in recursive node and byte accounting and still render as one bounded settings card. AGY catalog-format compatibility is handled by the CLI; no new Router capability is required.

From 1.6.155, the selected application scope is highlighted in blue. Model/effort selectors separate the current thread's main backend from other backends' worker preferences; the main role remains bound to the coordinator even while viewing another target. Same-backend worker preferences remain shared with the main backend.

From CLI and Router 1.6.156, delegationCards additionally gates a thread-scoped /delegation menu with On/Off controls and a separate, non-selectable availability section. The selected option stays unchanged while a request is pending or unknown and changes only after a matching CLI acknowledgement. Busy/queued work disables toggles; Refresh remains available. The Router does not launch workers or bypass sandbox restrictions. Both capabilities are required for the new menu; older peers and parameterized text commands retain their behavior.

Backend availability uses colored status badges: blue for the coordinator, green for installed workers, orange for blocked workers, red for unavailable backends and gray for unknown worker availability. Text labels and version or restriction details remain visible; these badges do not prove authentication or quota.

Choices use opaque stored tokens rather than command text or stale ordinals. Callback ownership includes the delivered card, original user/device/thread, connection, snapshot and page revision. Show all model/effort choices when the complete card fits its recursive tagged-node and serialized-byte budgets; only oversized catalogs paginate, using the capacity of each page rather than a fixed eight-choice limit. Include headers, groups, navigation, notices and pending/retry controls when packing and updating cards. Missing backends are disabled, native-unavailable states remain explicit, and expired or stale controls require a fresh menu. Socket changes invalidate action bindings. No native settings, credentials, installations or model inference run on the Router. Older peers retain text lists. See Model and Reasoning Effort.

Illustrated Tips

Use /tips to browse 27 short Chinese scenario cards, each with its own bundled illustration based on the actual settings panels or task cards, a benefit, and a copyable example. Examples are educational text; card buttons never execute them or change backend, model, effort, device, or thread. Browsing works for bound users even while their CLI is offline. Copyable examples appear directly below the usage instructions, followed by usage notes. Cards offer only Next, Mastered, and Settings controls.

The library includes directory browsing, named project threads, tool-row details, managed delegation controls and worker resets, Codex speed and goals, and native command sandbox settings. Backend-specific tutorials explain their prerequisites; examples and illustrations never activate those features themselves. Two Easter-egg tutorials explain the Codex weekly-quota and banked-reset-credit notifications. These are passive status snapshots: remote-cli does not grant, claim, or consume reset credits, and reading a tip never starts a model task.

| Command | Result | | --- | --- | | /tips next / /tips list | Read another tip or browse the library | | /tips settings | View subscription, mute, and timezone settings | | /tips daily / /tips weekly | Explicitly subscribe daily or on Tuesday and Thursday | | /tips mute 7 | Pause automatic tips for seven days (1-365 supported) | | /tips unmute | Remove the pause without enabling a disabled subscription | | /tips off | Disable automatic tips permanently until explicitly subscribed again | | /tips timezone Asia/Shanghai | Select the IANA timezone for this user's schedule |

Automatic delivery is daily by default. Tips are due at 10:30 in the user's timezone (default Asia/Shanghai), within 10:30-19:00 only, at most once per local day and at least 20 hours apart. Delivery requires a bound online device, bot activity within seven days, two minutes of quiet, and no task currently visible to the Router. This check cannot observe every backend-local operation or queue. Offline periods create no backlog; device registration never triggers tips. Settings cards offer 1/3/7/14-day mute controls. Seen or mastered tips are skipped. Existing default-off records adopt daily delivery; explicit opt-outs, mute deadlines, chosen frequencies, reading progress, and delivery cooldowns are preserved.

The Router stores private per-user preferences and delivery intent beside its configuration. A send with an uncertain result is suppressed rather than replayed. Run one Router process per storage directory; this is not multi-replica delivery. Optional Router configuration tips.enabled: false disables automatic delivery globally while retaining browsing; tips.timezone sets the default IANA timezone. Tips use reviewed bundled content and static PNGs, with no model calls or catalog probes. Some examples require a compatible CLI; the backend tip includes the text command alternative for clients without settings cards.

Maintenance Notices

From CLI and Router 1.6.127, upgrade notices use concise Chinese summaries from RELEASE_NOTES_ZH.md, with one short title and bounded user-visible changes per release. CHANGELOG.md remains the English technical record. The CLI build requires matching current-version entries in both documents and bundles both, without online translation or model calls. New Routers show summaries directly and collapse technical details. Earlier maintenance-capable Routers show the summary in their existing collapsed panels; new Routers keep older CLI notes collapsed when no technical-details field is present. Cumulative ranges, silent first adoption, delivery acknowledgements, and protocol version 1 are unchanged.

From CLI and Router 1.6.128, upgrade cards group changes by stable feature tags across each device's full pending version range, not just the current detail page. Exact duplicate items are removed within a feature; distinct changes remain available in paged version records. Feature tags are stripped from display Markdown and never shown to users. The overview is bounded to 6 KiB, six features, and 12 items, with explicit omission counts; all bundled summaries and technical records remain in collapsed version details. Older metadata or insufficient overview space falls back to the existing per-version display. The optional overview preserves protocol version 1 and old-peer behavior, without model calls or changes to first adoption, notification progress, or acknowledgements.

CLI and Router 1.6.134 consolidate the available 1.6.90-1.6.133 release records and confirmed source history into one stage summary. Upgrade notices for devices with an existing notification baseline show that complete summary, not an exact per-device subset; some changes may have been delivered before. The old version sections in this range are no longer bundled or available through package-backed detail paging, but remain in Git history. Earlier changelog records are unchanged, first adoption stays silent, and subsequent releases resume normal incremental entries. From 1.6.134, each release may contain one to six summary bullets within the unchanged 2 KiB budget. This release changes release documents, package versions, and summary validation only; backend execution and Router behavior are unchanged.

Router and CLI 1.6.123 negotiate optional upgrade-notice and subscription-inspection capabilities without changing protocol version 1 or old-client traffic. Upgrade cards show cumulative bundled release-note ranges; first feature adoption is silent. The Router resolves the original device owner and acknowledges only after successful delivery and a private durable receipt. Receipt retention is 30 days and 1,000 entries; deduplication cannot guarantee exactly-once delivery across a Feishu-success/storage-write crash. View more requests the same bundled range from the connected compatible CLI, without external changelog fetches or persistent paging sessions.

Codex inspection and account state belong to the local CLI, not the Router. Its experimental native login API may change; unavailable inspection does not affect messaging. Subscription reminders are independent, notification-only cards, never user-thread output or routing controls. Backend-specific copy is selected by an optional backend identifier; legacy messages without it retain Codex handling, and unsupported identifiers are rejected. Codex explains possible reset-countdown drift and tells the user to send a normal task to start the next usage window, without verification steps. Its 100% weekly availability is a snapshot from the qualifying checks, not a live balance, confirmation that a reset occurred, or a guarantee about when a usage window starts. New reminder cards have no buttons; validated legacy Dismiss callbacks remain passive. There is no Send Hi button or automatic activation, and reminder actions never send model requests. Older peers remain usable. See Maintenance Notices for first-start, offline, privacy, and opt-out behavior.

From Router 1.6.125, quota reminder cards use the title 🎯 Codex Reset and summary Weekly quota reset: 100%, without the sampling-disclaimer footer. From Router 1.6.126, new quota cards have no buttons; validated legacy Dismiss callbacks remain passive. Normal-task guidance and inspection criteria are unchanged.

From CLI 1.6.126, acknowledged quota-reminder suppression survives upgrades and restarts in a private local ledger under ~/.remote-cli/subscription-reminders/, scoped to the Router and device. It stores only hashed account/bucket fingerprints, not tokens, raw account identifiers, credential metadata, reset timestamps, or quota observations. Credential refreshes do not clear suppression; only a valid non-candidate observation rearms that account. Missing/failed probes retain suppression. Sampling baselines remain in memory. Accepted acknowledgement writes finish before graceful shutdown; corrupt, unsafe, or unavailable storage pauses quota inspection and reminder delivery without erasing the ledger or affecting normal messaging.

Deduplication is not exactly once: a crash between card delivery and local acknowledgement persistence can still produce a duplicate. Earlier clients retain process-only suppression, and their delivery history cannot be recovered on first adoption of the ledger; one additional qualifying reminder is possible. The Router presentation change alone does not give an older CLI restart-safe suppression.

From CLI and Router 1.6.150, the same startup/hourly status read also checks native rateLimitResetCredits.availableCount. A Codex Banked Reset card is sent only when the current valid count exceeds the previous valid count for the same account. The first sample, account switches, and service restarts establish silent in-memory baselines. Equal counts and decreases do not create notices; decreases update the baseline (for example, 5 → 3 is silent, then 3 → 4 notifies). Missing or invalid counts are unknown, not zero, and retain the last valid count for that account. Credit details may be absent or capped and are not used to infer the count. Pending increases are replaced by newer increases and canceled after an observed decrease or account switch; ACKs stop retries for that event only, never suppress later growth. Banked delivery receipts stay in Router memory until notice expiry, bounded to 1,000 including in-flight creations. Lost-ACK retries after a CLI reconnect acknowledge the existing card after revalidating ownership instead of creating a duplicate; socket/action bindings remain invalidated. Router restarts or ambiguous creation outcomes can still duplicate delivery. Delivery is best effort, and the card shows the previous/current counts and increase at the latest check, not a live balance. The additive bankedResetReminder capability requires both peers to opt in, so older Routers never render the new notice as a weekly reset. The existing maintenance.subscriptionInspection setting controls both quota notices. No extra status request, model prompt, automatic reset-credit consumption, or expiry notice is added.

Claude tool-result content blocks are normalized to text by the CLI; embedded media and unknown payloads are not scanned for local files. Local image detection and forwarding are best-effort: failures do not fail the task or terminate the CLI. Web-result excerpts remain excluded from local-file scanning.

CLI and Router 1.6.173 add direct forwarding for recognized successful Codex native image results, MCP image blocks, and dynamic-tool inline images. These images do not require a Markdown link. Native saved-file references use the same local directory policy as Markdown images. Structured extraction does not traverse arbitrary JSON path fields or publish image-view events, and remote URLs are not fetched. Ordinary tool-result text retains local-path detection; shell tools that return only text still need a local path or Markdown image link.

Each reply accepts up to 32 image candidates and displays up to 8 distinct images, with a 2 MiB decoded limit per image. Supported raster formats are checked from their bytes. Local files must pass canonical directory and regular-file checks; denied, missing, invalid, oversized, or timed-out images produce a bounded omission notice while text can still complete. Identical bytes are deduplicated within the reply, including native and Markdown copies; changed bytes at the same path can be displayed again. Reads and uploads have bounded concurrency and waiting times, and late results cannot be attached after cancellation or replacement.

Upgrade both CLI and Router for the complete fix: the CLI discovers and validates images, while the Router waits for admitted uploads before completing the card. The image wire format remains compatible with older image-capable peers, but an older Router retains its upload/finalization race. Delivery is best-effort with no image replay across disconnects; a model saying it sent an image is not a delivery acknowledgement.

Overview

The router server acts as a bridge between Feishu messaging and developer machines running the remote-cli client. It handles:

  • User-device binding via Feishu bot commands
  • Message routing between Feishu and connected CLI clients
  • Code-change rendering with collapsible, line-aware diff previews inside streaming cards
  • Image message forwarding for Feishu images to supported backends, plus Codex native image output and local image files returned by any backend
  • Client service management is handled by the local CLI; the Router remains a separate long-running server process
  • Queued task cards appear at execution time for capable clients, with the thread, workspace, task preview, and remaining queue count; older clients retain waiting cards
  • Delegated task progress uses the existing reply and approval cards. With a supporting local CLI, Claude Code, Codex, Pi, AGY, OpenCode, Kimi Code, ZCode, and DSH can work within the selected thread; the Router does not run or select workers. From CLI 1.6.142, managed delegation accepts any eligible installed backend, including the coordinator backend through independent worker sessions. An unrestricted coordinator launches unrestricted workers; sandboxed coordinators have no eligible workers, including on the same backend, until scope-aware worker sandbox preservation is supported. Native backend task/subagent tools are unchanged. Other backend approval options still apply. This policy is enforced on the local CLI and requires upgrading it; the wire protocol remains unchanged. See Cross-backend Delegation.
  • WebSocket connections from local clients
  • Feishu long connection for receiving and sending messages
  • Task recovery with compatible clients: resume output on a usable surviving card or create a new one, with an independent gap notice and plain-text handling of resumed fragments; failed card creation or recovery-notice updates are not acknowledged as successful recovery
  • Table-aware card splitting and a single text fallback retry for a card rejected by Feishu's table limit or Markdown parser

Router 1.6.91 extends the text fallback to confirmed Markdown parse errors (11311). It retries the affected card once with Markdown shown as literal code text, and retains that format for later updates and thread-button refreshes. Other cards keep their normal formatting. Older CLIs remain compatible; this fallback requires only a Router upgrade.

Router 1.6.92 requires successful recovery-notice delivery before acknowledging reuse of a surviving card. A failed update can retry within the same recovery round without duplicating the notice. Update-failure logs identify the root reply, affected card ID and number, and Feishu error and trace codes without logging the card body. Older recovery-capable CLIs remain compatible.

Router 1.6.90 checks tool parameters before using specialized card formatting. Missing or incompatible fields fall back to a bounded parameter summary; missing input shows a no-parameters placeholder. Later tool events and task completion continue normally. Older CLIs remain compatible; backend execution and the wire protocol are unchanged.

Supporting CLIs enforce delegated task completion locally: they suppress stale coordinator prose while results are missing from the active execution and keep the parent request busy until those results have reached the coordinator. Early returns trigger a continuation in the same session, without replaying the original request or attachments. The Router displays the existing task progress and reply events; no new protocol capability is required for this completion barrier.

From CLI 1.6.129, one request may accept multiple independent delegated tasks before collecting results, executing them in FIFO order with one active worker. Queued tasks are independently cancellable and have no started progress card. Their bounded status notices use the existing text channel, not a new wire phase; old Routers remain compatible and old CLIs keep their existing behavior. The 12-task cumulative limit and one-hour queue deadline are enforced locally. Other overlapping requests are rejected rather than globally queued. This does not add peer communication or modify native backends or Router execution. Sibling results are not explicitly forwarded; a reused same-backend lane retains its own earlier task context. Uncertain native startup or exit retains the occupied global slot until the local CLI restarts.

From CLI 1.6.139, Git delegation has no fixed repository size or file-count limits during snapshots, artifact collection, or checkout verification. Git command deadlines and buffered-output limits still apply. Path, ownership, artifact-integrity, and unknown-file checks remain in place. This is local CLI behavior; upgrading only the Router does not remove an older CLI's limits.

From CLI 1.6.141, local initialized submodules and embedded repositories also contribute staged, unstaged, and nonignored working files. Their Git metadata and history are not copied into the worker; explicit integration preserves every source HEAD, index, and gitlink. Uninitialized submodule paths stay empty without fetching a remote. Worker-created nested repositories or changes to those empty paths require manual recovery and explicit retention, even with unchanged files. Nested worktrees sharing an ancestor, external metadata pointers, partial clones, and nested-local filter commands require recovery or exclusion. System/global Git configuration remains trusted; the existing Git transfer deadline still applies. A hard kill can leave a transfer quarantine requiring manual cleanup after its processes exit. Tracked submodules also matched by outer ignore rules currently fail admission; reconcile those rules before delegating.

From CLI 1.6.151, checkpoint index queries are combined and identical trees are audited once within a capture. Both working-file passes and source HEAD/index checks remain; no state is cached across tasks and Git deadlines are unchanged. From CLI 1.6.153, real Git fixture suites use at most two isolated processes (one on hosts with fewer than four available CPUs), alongside one to four lightweight test threads. Pristine test repositories are copied into independently owned directories instead of rebuilt for every case. Publish still runs the full suite; ordinary test deadlines and production Git safety checks are unchanged. From 1.6.154, filesystem checks run in batches of at most eight and drain before failure; checkout readers still hash every byte with independent buffers up to 1 MiB each. Test-only clocks remove mocked startup/stop and transfer-deadline waits after readiness gates; real Git streams, partial packs, cleanup assertions, 129 MiB files and 10,001-file stress coverage remain. ZIP fixtures use faster CRC generation without changing archive bytes. Hosts with at least eight available CPUs use at most four isolated Git processes plus at most four lightweight threads; lower-core pool limits and ordinary deadlines are unchanged.

From CLI 1.6.140, managed Git preparation, repository-lock waits, and artifact collection are awaited separately from native startup/stop deadlines. Slots and source reservations remain held until owned operations settle, even on cancellation; no late worker is launched. Failed collection after confirmed exit preserves only the affected lane and files for recovery rather than quarantining the source. Individual Git command deadlines remain; cancellation may wait for Git to settle. From CLI 1.6.159, delegated git worktree add and git checkout commands have a 120-second deadline per command. Other Git commands, including worktree listing/removal and nested object transfers, retain their 15-second deadlines. Git command timeout errors show the operation, elapsed milliseconds and deadline without paths or checkout references. Preparation remains pending until the Git child exits; cancellation can wait for this bounded cleanup, and the existing task ID remains available for polling.

From CLI 1.6.193, a failed or timed-out nested Git transfer disconnects its input pipe and drains pending output before awaiting both child exits. This prevents a full pipe from keeping delegation cleanup pending after the processes have exited. Partial transfer data is removed only after both children close; unrelated temporary directories remain untouched. Upgrade the local CLI for this fix; a Router-only upgrade does not change local Git handling. Slow launch/cancel tools return the accepted task ID and a pending status before the adapter timeout; poll that ID with remote_cli_result, not a new delegation. The response does not claim cancellation cleanup or workspace release is complete. Checkpoints reject assume-unchanged and skip-worktree entries rather than omitting hidden edits or treating missing sparse files as deletions. Resolve those flags and sparse checkouts explicitly; the source index is never modified. These changes require a CLI upgrade; Router protocol and native backends are unchanged.

CLI 1.6.192 fixes a CommonJS runtime error introduced in 1.6.191 that prevented delegation backend discovery and task admission. Upgrade the local CLI to apply the fix. Router-only upgrades do not repair the installed CLI. Artifact export validation and canonical storage-path checks retain their existing behavior. On Linux and macOS, SIGTERM and SIGINT await client and worker teardown before process exit, including during startup. Verified normal shutdown releases the delegation storage owner before restart; failed or unconfirmed worker teardown retains recovery state and exits unsuccessfully.

Ownership now uses a native OS lock held on a stable .ownership.guard file, plus checksummed owner identity and a durable .ownership.children process journal. Completed history is compacted atomically; unresolved launches remain recorded, and failed lock releases can be retried without restarting. The empty guard file intentionally remains after release: its existence does not mean the storage is busy. Never remove or rename it while a CLI may be running. Native binaries are bundled for supported Linux, macOS and Windows architectures; unsupported native-lock platforms fail explicitly rather than falling back to an age-based lock. Use local filesystems; shared/network storage is not supported.

A crashed idle owner can be recovered automatically. On the same host after a reboot, old process evidence no longer blocks acquisition. On the same boot, recovery validates PID/start identity and checks each recorded POSIX process group with the kernel; surviving children, unknown launches, foreign hosts/PID namespaces and incomplete journals remain protected. No process is killed by recovery, and no worktree, artifact or conversation is deleted just to regain ownership. Recovery does not authorize workspace disposal; existing artifact and checkout checks still apply. Groups escaped via setsid/setpgid are outside the existing managed-process-group guarantee. Windows crash recovery with recorded children remains conservative because process-tree exit cannot be proved from a PID alone. A crash between spawning a child and saving its identity also remains protected until a proven reboot or controlled recovery.

Version-1 lock files from 1.6.191 lack boot and child evidence. They require a one-time quiescent recovery if the old process did not shut down cleanly; the CLI never steals them based only on PID or age. Upgrade the local CLI to activate these changes; updating Router alone is insufficient.

From CLI 1.6.191 on Linux, newly created managed Git worktrees are disposable execution storage. After confirmed native process-group exit, successful delivered output and failed no-change output can release the entire checkout, including ignored dependencies and temporary extras. Captured failed changes are retained as immutable Git artifacts for recovery without merging; explicit retention also permits checkout cleanup. Native conversation pointers, artifact records and private Git refs stay available. The next task recreates the same lane path from fresh delivery input. Pending successful changes wait for apply or retain. Uncertain process exit, uncaptured source edits, incomplete deliverables, unsafe paths and unresolved parent-application recovery remain explicit holds. Unknown legacy records do not silently inherit the disposable policy. Reusing a pre-upgrade checkout also keeps its original policy and ignored files; adoption requires strict reclamation and creation of a fresh checkout, or explicit offline historical disposal. On macOS and Windows, ordinary delegation keeps the existing conservative checkout policy; the new whole-checkout disposal is not enabled. Linux delegated workers use isolated process groups, including Codex, Claude and Pi. Group confirmation remains separate from transport exit and holds the checkout on uncertain identity, inventory or termination. Kernel-visible unreaped zombies also hold cleanup until the group disappears; an empty process snapshot alone is never sufficient. It covers members of that group; background processes that escape using setsid or setpgid are not covered and must not write into disposable worker checkouts.

Cleanup uses durable intent and receipt records. Failed removals are retried on startup and while idle; cleanup failure does not undo integration or turn a successful task into a failed task. Failed/retained receipts support reconstruction as well as deletion. Required reports and images must be captured or durably exported before cleanup; merely returning a path in the temporary checkout does not deliver the file. Declare required relative file paths in the delegation tool's optional exports array (up to 16 files, 16 MiB each, 64 MiB total). Artifact inspection returns verified durable local file locations. Missing or changed exports hold cleanup instead of silently dropping the deliverable. Unsupported transformed or nested checkouts remain held.

One owner coordinates mutable local delegation storage. Lane admission excludes cleanup, and cooperating CLI processes serialize shared Git metadata operations by canonical Git common directory. Independent workers still run concurrently. Unmanaged writers and old CLI versions do not participate in this ownership protocol. A stale owner or uncertain child exit requires a confirmed quiescent maintenance handoff; age or a missing parent PID alone never authorizes deletion. Historical disposal is an explicit offline operation, not an automatic upgrade sweep. It preserves parent projects, existing artifact refs and native sessions.

Inspect locally with remote-cli delegation storage scan. Freeze a cleanup plan with remote-cli delegation storage plan --out ./discard-plan.json. After stopping the daemon, supervisors and all native workers, run remote-cli delegation storage discard --plan ./discard-plan.json --discard-contents --confirm-workers-stopped from an independent terminal. This permanently discards checkout contents, including unsubmitted and ignored files. The command never stops or restarts a service. Retained session records receive scheduler exclusion markers so a removed historical checkout is not resumed automatically. This explicit discard can lose uncaptured state even for a lane labelled ready; it preserves native history, not automatic continuation. Ordinary new-policy reclamation still recreates the same lane and preserves continuation.

The inventory includes integration scratch and its receipts. Registered scratch with matching ownership evidence can enter the explicit frozen discard plan; unknown, conflicting-identity or unregistered directories stay listed with their exclusion reasons. Discarding scratch leaves its originating lane and native session unchanged. Conflict scratch is never deleted automatically. Completed discard markers bound to the original task and workspace retire unavailable checkout obligations without claiming successful delivery. Older, unbound or pending markers remain conservative. Incomplete inventories warn about unseen records; known pending tasks still require closeout and incomplete scans never authorize automatic deletion.

The scan defaults to 100,000 entries, 1 GiB of hashed content and 120 seconds; use --max-entries, --max-bytes and --max-seconds to increase explicit budgets. An incomplete inventory cannot authorize deletion. Local output contains paths and identities and should not be forwarded to chat. Offline deletion currently requires Linux mount inspection; unsupported platforms refuse deletion. Ownership uncertainty, stale locks and ambiguous partial removal require manual quiescent recovery. Neither this command nor automatic cleanup prunes Git objects or refs.

This lifecycle requires a local CLI upgrade. Router messages and the protocol remain unchanged; older CLIs keep their existing lifecycle with a newer Router. The upgraded CLI also recognizes successful worker snapshot commits already in delivery HEAD's ancestry. A later revert does not reopen historical delivery. Inspection, ready-lane admission, and idle closure reconcile only that thread's owned lanes; safe file-reclamation checks remain independent. This is local CLI behavior, not a Router-side merge, content comparison, or new protocol requirement. From CLI 1.6.136, the CLI checks durable artifact disposition before successful coordinator completion and can resume the same session for at most two closeout rounds. Missing, invalid, pending, or unretained recovery state fails the final response if unresolved, with task IDs and available output commits, while preserving artifacts. A deliberate retain settles the decision without claiming delivery. The Router renders existing progress/error messages; no new protocol, automatic merge, or old-request replay is introduced. Older CLIs keep their current behavior.

From CLI 1.6.138, already settled artifact receipts are validated without requiring an idle source workspace; another busy thread does not reopen completed delivery. Pending or unverifiable outcomes still require closeout, and history reconciliation still requires the source lease. Reused Git lanes remain reusable after confirmed failures before checkout preparation starts; uncertain checkout or executor setup continues to preserve the lane for manual recovery.

From CLI and Router 1.6.137, finished Worker cards expose Clear context outside folded details, including failed tasks that established a worker lane. The button disconnects only that worker's native conversation continuation. It keeps the coordinator, other workers, workspace files, artifacts, login, and settings intact; archived native transcripts are not erased. The next delegation starts fresh, with no automatic retry of the failed task. Only the original user can operate the control on its original device. Running workers, unconfirmed shutdowns, and stale cards after lane reuse are rejected. Context cleared appears only after CLI acknowledgement; timeouts and failures allow explicit retry. An interrupted clear stays non-resumable until a retry finishes. From CLI 1.6.138, retrying an old shared-directory lane's clear after a replacement has been created clears only the old continuation, without reviving that lane or scheduling the replacement for deletion. Ambiguous duplicate lanes are preserved for manual recovery; independent Git worker lanes remain reusable. Controls require both peers to advertise workerContextReset; old peers retain their existing behavior. Card controls expire on Router restart, after 24 hours, or when their bounded cache is evicted; use a newer card or the existing thread-scoped /delegation reset [backend] command when idle.

CLI 1.6.94 and newer show each finished worker as a result block in the existing reply card, with a colored status label, backend name, short task description, and elapsed time. Failed, timed-out, cancelled, and interrupted tasks include a bounded reason; the coordinator still receives the existing task result. This uses the existing text stream and works with older Routers. It adds no probes, cooldowns, retries, or changes to ordinary non-delegated sessions.

CLI 1.6.95 no longer aborts workers because their intermediate text or tool results exceed a cumulative output threshold. Individual results remain bounded to 32 KiB and combined result continuations to 64 KiB. Oversized result text keeps its beginning and end with an explicit truncation marker and flag; truncation does not change the task's success or failure status. These limits bound retained delegation results, not backend output buffers. Worker timeouts, cancellation, and cleanup still apply. This requires a local CLI upgrade and works with existing Routers.

With CLI and Router 1.6.167 or newer, terminal Worker card excerpts retain up to 4 KiB of UTF-8 text. Excerpts containing standalone omission markers are shown as escaped plain text with a separate explanation rather than interpreting contextless Markdown fragments. Intact result Markdown is preserved. Upgrade both peers for the larger preview; newer Routers also safely display older CLI omission markers. Older or unknown Routers keep the legacy 1000-byte head/tail summary, including after reconnect. The 32 KiB result and 64 KiB continuation limits stay unchanged.

CLI 1.6.89 can compact/retry result continuations that launched no new workers. Results remain retained until the coordinator execution succeeds. If its reply still fails, bounded completed worker results appear as plain text alongside the failure; no new wire capability is required. Abort/shutdown suppress this fallback. It does not provide automatic recovery on a later request or guarantee delivery across disconnects/restarts.

Router 1.6.117 and newer explicitly label standalone background-task notifications Background task. The status, originating thread name (or thread ID when no name is provided), and abbreviated task ID remain visible, while View details is collapsed by default and contains the rich Markdown result and optional output path. Failed tasks also show a short, literal failure summary outside the panel. This changes only the Router presentation: the CLI protocol, foreground replies, delegated-worker cards, and reply-to-thread routing remain unchanged.

Prerequisites

Image uploads require the bot application's im:resource permission. Publish permission changes in the Feishu developer console before retrying an upload. Router 1.6.85 and newer render local and URL-based Markdown image references as captions, with uploaded images in separate card image components. Code examples and inline Feishu img_ keys are preserved. Older CLIs remain compatible. Router 1.6.89 also recognizes Markdown list and quote boundaries, so images inside those containers are filtered while actual code examples stay unchanged.

  • A server reachable by your local CLI clients, with outbound access to Feishu
  • Node.js >= 18.0.0
  • For public deployments, a domain name and TLS reverse proxy for client connections; internal deployments can use HTTP on a trusted network
  • A Feishu bot with messaging permissions

Installation

npm install -g @yu_robotics/remote-cli-router

Quick Start

1. Configure

remote-cli-router config

You will be prompted for:

  • Feishu App ID (required)
  • Feishu App Secret (required)
  • Feishu Encrypt Key (optional)
  • Feishu Verification Token (optional)
  • Server Port (default: 3000)

Configure the bot's Long Connection event mode with im.message.receive_v1 and card.action.trigger. The Router opens the connection to Feishu; no inbound Feishu webhook URL is required. Encrypt Key and Verification Token are retained in the configuration wizard but are not used by the current long-connection handler.

2. Start the Server

remote-cli-router start

3. Deploy with PM2 (Production)

pm2 start remote-cli-router --name router -- start

Docker Compose (Recommended for Shared Routers)

From the repository root, build the Router image and run the interactive setup once:

docker compose build
# Optional: copy .env.example to .env and set ROUTER_PORT first
mkdir -p router-data
docker compose run --rm router config setup
docker compose up -d

The ./router-data bind mount stores Router data under the container's /router-data home directory (/router-data/.remote-cli-router/). On Linux, set ROUTER_UID and ROUTER_GID in .env to the output of id -u and id -g; they must match the directory owner. Set ROUTER_PORT before setup if port 3000 is unavailable; it must match the server port entered in the setup wizard. The Compose service uses restart: always, so Docker starts the Router again after unexpected exits and Docker daemon restarts; docker compose down still removes the container. Use docker compose logs -f router to inspect logs and docker compose down to stop the service. Run local clients directly on their host machines rather than in Docker so they can access project files and local AI CLI binaries.

From Router 1.6.184, startup accepts a stale PID record that points to the new startup process itself, including PID 1 after Docker recreation. Startup failures and shutdown attempt bounded cleanup of the current instance's PID record. Abrupt termination can still leave a record; successful cleanup is not required for this self-PID recovery. Run only one Router per storage directory. This does not provide concurrent-start locking or identity checks for unrelated reused PIDs.

Clients automatically install a newer Router's exact published npm version when their tasks and queues are idle. Manual clients continue running the old version until their next start; clients launched with --non-interactive exit for their supervisor to restart. A rejected CLI protocol requires a restart after installation. Publish the matching CLI package when upgrading the Router.

Commands

| Command | Description | |---------|-------------| | remote-cli-router config | Interactive configuration | | remote-cli-router config show | View current configuration | | remote-cli-router config reset | Reset to defaults | | remote-cli-router start | Start the server | | remote-cli-router stop | Stop the server | | remote-cli-router status | Check server status |

The Feishu command reference includes the cross-backend /status, /context, and /skills commands, the /clear and /new fresh-conversation aliases, plus per-thread queue controls. See the root README for the complete command and backend behavior reference.

CLI 1.6.93 makes /cd to a different directory start fresh conversations for all backends in that thread, including inactive ones. Returning to the old directory does not restore its old conversations. Same-directory /cd and backend-only switches preserve context. Thread settings and native history files remain intact. The CLI enforces this behavior without a protocol change; upgrading only the Router does not change an older CLI's directory behavior.

From 1.6.168, directoryCards is an optional capability requiring settingsCards on both peers. Bare /cd becomes a directory-only browser; older peers retain text /cd <path>. Router reuses settings-card owner/device/delivered-card/revision binding, pending suppression, and exact-request confirmation. Child, Parent, roots, and refresh actions query the original CLI with opaque tokens; Router never reads the CLI filesystem. Only Use this directory applies a cwd change; Cancel closes locally. Navigation leaves context unchanged. The CLI checks policy, snapshot, directory/ancestor identity, busy/queue state, and shared mutation admission at Apply. Large lists use budget-driven paging and bounded scans with explicit omissions. Directory symlinks are omitted, and Parent stops at the nearest allowed root. These checks are not an OS sandbox or complete protection from concurrent filesystem changes or bind mounts. Protocol version remains 1.

With CLI 1.6.84 or newer, /status also shows Delegation: on/off (current thread). The CLI reads this effective setting without initializing delegation or starting workers.

From CLI 1.6.121, new and existing threads without a saved delegation preference default to on. Explicit /delegation off choices remain off across upgrades, context resets, backend switches, and restarts; /delegation on re-enables it. There is no historical thread migration or automatic worker launch. Upgrade and restart the local CLI, not just the Router, to obtain the new default. The Router protocol is unchanged, and older CLIs retain their existing default.

From CLI 1.6.118, /status shows DSH's official recharge and bonus wallet balances when available. Native official-account sign-in is required; API-key-only or custom-provider setup does not supply these wallets. Amounts retain their native decimal precision and currency; balances are not token usage or plan quota. The query does not create or change an ACP conversation. Its owned process uses the same log-upload and telemetry suppression as the DSH executor, is stopped after the query, and omits the balance section on failure or timeout. No other backend or Router protocol changes are required. From CLI 1.6.120, Claude SDK [claude-code:unrecognized_model] diagnostics are omitted from Feishu streaming/results and Claude slash-command error details. CLI 1.6.124 also filters the generate_session_title source, including delegated Claude workers. Matching requires a bounded, standalone valid JSON record containing only a nonempty model string and a recognized query_source (sdk or generate_session_title); model names are not hard-coded. Unknown sources, additional payload fields, malformed records, actual API/authentication errors, exit status, and assistant reply text are retained. The persistent Claude process's raw stderr remains in local CLI logs; this presentation filter does not disable Claude Code telemetry or change the configured model, other backends, or the Router protocol.

Older CLIs keep their existing status output.

Architecture

Remote CLI architecture

Nginx Reverse Proxy

server {
    listen 443 ssl http2;
    server_name your-domain.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
    }

    location /ws {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
        proxy_read_timeout 86400;
    }
}

Health Check

curl https://your-domain.com/health
# {"status":"ok","timestamp":1234567890,"connections":0}

Advanced Usage

From CLI 1.6.190, Kimi and OpenCode permission decisions use the standard nested ACP v1 response, so automatic or explicit approvals and cancellations can be interpreted correctly by the backend. Upgrade the local CLI; a Router-only upgrade does not apply this fix. Existing approval policies are preserved: disabling automatic approval still requires user input, and model questions remain interactive. This does not enable Kimi native Never Ask mode or change global backend configuration or saved conversations.

From CLI 1.6.175, opening or refreshing Kimi's /model list also refreshes the native OAuth-managed model catalog through Kimi's authenticated loopback server. Manual terminal refresh and repeated sign-in are not required. Kimi must expose the native model-refresh endpoint; account permissions and upstream availability still determine the returned choices. Failed or timed-out refreshes are reported rather than treated as a successful refresh of an old list. Upgrade the local CLI to use this behavior; the Router protocol is unchanged. Applying a discovered model to an idle Kimi thread reloads the native ACP process and resumes the same conversation binding, so its process-local catalog cannot reject the new alias.

From CLI and Router 1.6.176, the /model card includes a separate Speed section when the selected Codex model advertises native service tiers. Choose a native tier, explicit Standard, or Follow native config. Native names and descriptions are preserved; Fast is a processing tier, not an invented model ID, and availability and usage depend on the native backend and account. Speed is saved per thread/backend and applies to future delegated workers and native goal continuations. Model changes that conflict with a saved speed are refused until Follow native config is selected. Untouched threads keep native behavior without extra speed settings requests. Both peers must negotiate model speed settings; older peers, Kimi Highspeed model IDs, and OpenCode models/variants keep their existing paths. If a saved speed disappears, a recovery-only Speed section retains Follow native config. Older native protocols that cannot safely clear a saved conversation's tier require a Codex upgrade or /clear before that conversation resumes.

Use one Router for multiple trusted clients. Each client connects from the developer's machine, while the Router owns Feishu configuration, device bindings, routing, and thread switch state. Feishu thread buttons show automatic names such as thread-2 as their sequence number, such as 2, while callbacks retain the full internal name. Continuation cards repeat the thread and working-directory header of the original card. A thread can override its backend with /backend <index> @; /backend <index> changes the global backend and clears per-thread overrides.

Thread switch panels show Reply from: with the reply's full thread name and workspace. Under Switch thread, a check mark (✓) and primary button styling identify the destination of new top-level messages when the card is finalized or clicked. Selected buttons remain clickable. Switching updates only the clicked card; other historical cards retain their last displayed selection.

From Router 1.6.174, completed cards show thread-switch buttons and + New directly, without a folding panel or an extra expand click. The reply-source caption remains visible, and thread selection keeps the existing routing and permission checks. Cards use a 180-tagged-node budget, including nested controls and reserved completion elements; size and table limits still apply. This presentation change requires a Router upgrade and does not change the CLI wire protocol. Previously sent cards are not automatically rewritten by an upgrade.

From Router 1.6.189, the selected thread for new top-level messages is stored per Feishu user and bound device, so Router restarts and device A→B→A switches restore it without resetting native sessions. A device with no saved selection keeps the existing default behavior. Replies to known cards remain independent of that selection; unknown or expired parent cards return an error instead of silently using selected/default. A confirmed deleted selection resets with a Feishu notice, and the failed message is never replayed. If a saved preference is corrupt, /thread list is a narrow read-only recovery path that refreshes selection controls from the bound CLI; arbitrary work still blocks. Continuation-card thread controls and replies retain the same provenance, and New Thread adoption requires a validated complete catalog. This requires only a Router upgrade and remains compatible with older CLIs over protocol v1.

From CLI 1.6.172, Codex threads support native goals through /goal (status), /goal <objective> (start), /goal pause, /goal resume, and /goal clear. Start or resume only when the thread and queue are idle, with managed delegation explicitly disabled using /delegation off. This initial restriction does not disable Codex's native subagents. Optional --budget <tokens> on start or resume sets an explicit positive token budget; omitting it does not invent a budget. For example:

/delegation off
/goal --budget 40000 Fix the failing tests and verify the public API stays compatible
/goal
/goal pause
/goal resume
/goal clear

Codex owns the persisted goal and automatic continuations; remote-cli keeps the execution card, approvals, and busy-state reservation across native turns. Status, pause, clear, and /abort remain available during work. Pause and clear stop current goal work; /abort pauses the goal, while clear removes the goal without clearing the conversation. After process loss, inspect with /goal and explicitly recover with /goal resume; status queries do not load or start the goal. Send attachments in an ordinary message before starting a goal. Use a Codex build exposing the native thread-goal APIs (verified with 0.163.0); unavailable APIs or disabled goals report an error. Other backends reject /goal. See the native goal API.

When a client thread is busy, the Router sends a confirmation card before accepting another message into its queue. /queue shows queue state, /queue clear discards queued messages, and /abort stops the active task and clears that thread's queue. Messages received while abort cleanup is in progress wait for the client backend to become safe before execution starts.

Expert Usage

The recommended production layout is Docker Compose on an internal server with persistent ./router-data storage:

git pull --ff-only
docker compose build --pull
docker compose up -d
docker compose logs --tail=100 router

Back up ./router-data before upgrades and do not use docker compose down -v for routine updates. Restrict the Router port to the trusted network. When diagnosing routing issues, inspect /health and the Router logs before restarting clients.

From CLI 1.6.177, /clear and its /new alias reset the entire current thread's conversation context: all direct backend session bindings and every managed worker conversation, across backends and parallel worker lanes. The working directory, files, Git artifacts, archived native transcripts, login, backend/model/effort selections, delegation preference, and sandbox grants are preserved. Other threads are unaffected. A later backend switch starts fresh instead of restoring a pre-clear binding. Busy tasks, queued work, and workers with unconfirmed shutdowns must settle before clearing. Reset intent is saved before any session binding changes. A persisted reset intent blocks old conversations until clearing succeeds, including after a CLI restart. If clearing fails, resolve the reported problem and retry /clear or /new. Service shutdown waits for retained cleanup and reports unconfirmed native exits before acknowledging completion. Single-worker Clear context controls still reset only the selected worker.

Session Resume

CLI 1.6.164 supports confirmed Pi native session connections and read-only Pi/Codex/Claude Code discovery. Adopted Pi history reloads before every remote turn; /session detach preserves it and /session release is removed. Foreground Pi /new and /clear also preserve old history and start independent IDs; new default names use native session IDs and persisted names are not overwritten on reopen. Worker/metadata cleanup is unchanged. Resume drafts keep ordinary messages in the current conversation until confirmation succeeds. Use only one side at a time. Local Pi windows may stay open but must use native /resume before their next local turn; automatic local refresh and writer locking are not provided. Existing Router command/response envelopes support the text workflow without a new wire capability. See the session resume specification.

From CLI 1.6.165, Pi connection and detach confirmations exclude simultaneous settings/context mutations and reject queued work, active delegated tasks, and automatic updates. One daemon reserves a selected Pi file before startup; successful connection/detach requires pointer persistence. Failed writes keep the previous association. Uncertain process cleanup keeps the selected file reserved; confirm Pi has exited before restarting the client to clear that quarantine. Discovery respects PI_CODING_AGENT_DIR, and Pi local reopen commands quote file paths. These guards do not lock unmanaged terminals or other CLI instances. Claude Code and Codex catalogs remain read-only; their executor, settings, and history behavior is unchanged.

Documentation

For full documentation, see the project README.

Upgrade compatibility

Router 1.6.185 retains protocol-v1 compatibility with existing CLIs, including legacy registration and response formats. Task output must belong to the connected device's bound user; binding requests and heartbeats remain available before binding. Device binding changes are serialized and persistence failures are reported rather than acknowledged as saved. Existing binding records keep their JSON format. Malformed binding files are preserved and stop initialization instead of being replaced with empty records. If a file replacement succeeds but its durability cannot be confirmed, binding reads and writes stop until the storage issue is resolved and the Router restarts to reconcile the saved file.

The ACP permission-error and Codex turn-start cleanup fixes are CLI-side changes: upgrade the CLI to receive them. Older CLIs can continue using the updated Router while retaining their previous local behavior. Legacy credentialless device identification keeps its existing trust limitations; this release does not require every older CLI to enroll a signed device key.

If Codex cannot confirm that its previous process stopped, the thread stays busy and does not start queued work. Retry /abort to confirm termination and release the thread. An unsuccessful retry reports the uncertainty and keeps the thread blocked; it does not replay the failed prompt.

From Router 1.6.187, binding files must have a supported version and valid record structure before they are loaded or migrated. Invalid files are preserved without replacement, and the rejected store instance blocks reads and writes. Correct or restore the file before restarting the Router. Valid version-1 files and versionless single-device files, including empty legacy collections, remain supported. The binding schema and protocol-v1 flow for existing CLIs are unchanged.

License

MIT

Changelog

See the project CHANGELOG.md for release notes and user-visible changes.

Approval Cards

When supported by the connected CLI, Codex and Claude Code permission requests appear as standalone cards with Allow once, Deny, and (for explicit directory grants) Always allow buttons. Buttons use the same column layout as thread-switch controls. Each button targets the original user, device, thread, and request. The card shows success only after the CLI confirms the decision. Completed requests cannot be approved again, and pending approvals receive fresh cards after reconnecting. After a Router crash, buttons on old cards may remain visible but are rejected as expired. Both CLI and Router must be upgraded to use this feature; unsupported peers and failed card delivery retain text approvals.

When the Router reports that an approval card could not be delivered, CLI 1.6.88 and newer show the requested action in a code block above the text reply instructions. This also applies to delegated worker approval requests, which never offer persistent grants.

Restricted Claude Code threads use the same approval card flow, titled Permission request, for outside writes, protected files, read-only-mode edits, and commands outside their native sandbox. Ordinary workspace and explicitly authorized directory edits in workspace-write mode do not create approval cards, unless a native ask rule requires one. If card creation fails, Claude accepts text replies without starting a new model turn; completed or expired requests cannot be approved later. The CLI enforces file boundaries before native allow rules; native deny and ask rules still apply. Sandboxed command networking is enabled by default, subject to native domain denials and administrator-managed restrictions; /sandbox network off disables it without changing the approval card flow. Missing sandbox dependencies stop execution on the CLI; the Router cannot override that startup failure. See Claude sandbox configuration.