Skip to content

feat(limrun): keep idle sessions alive with LIMRUN_KEEP_ALIVE - #3185

Merged
thymikee merged 1 commit into
callstack:claude/limrun-scoped-token-attach-c41afffrom
jbroma:feat/limrun-keep-alive
Oct 4, 2026
Merged

thymikee merged 1 commit into
callstack:claude/limrun-scoped-token-attach-c41afffrom
jbroma:feat/limrun-keep-alive

Conversation

@jbroma

@jbroma jbroma commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Limrun ends an instance after its inactivity timeout. An agent-device session that sits idle, for example while a model thinks between steps, loses its instance mid-run. With LIMRUN_KEEP_ALIVE=1, the Limrun runtime pings each leased instance every 30 seconds from the session's own client until the lease is released. It is off by default, so instance lifetime is unchanged unless requested.

export LIMRUN_KEEP_ALIVE=1
agent-device connect limrun --platform ios
new LimrunRuntime({ instances: { ios: { apiUrl, token } }, keepAlive: true });

Stacked on #3173: the flag is read in src/provider-limrun-credentials.ts, which that PR adds. 6 files, including help and the Limrun docs page.

Validation

At 77b62f4:

  • pnpm check:affected --run passes (139 files, 1043 tests).
  • Mutation check: skipping startKeepAlive fails the on/off and throwing-ping tests.
  • Live on Limrun iOS and Android instances (3 min inactivity timeout, 240 s idle while connected, no org key in the agent-device environment):
    • Without the flag, both instances ended terminated (InactivityTimeout).
    • With LIMRUN_KEEP_ALIVE=1, both stayed ready and snapshot -i succeeded after the idle. Release, daemon stop and a daemon SIGKILL still left the attached instances running.
  • Pings from a separate client kept the instance alive, but agent-device's ADB tunnel still went offline. That is why the session's own client sends them.

Review in cubic

Limrun ends an instance after its inactivity timeout, which idle sessions hit while a model thinks between steps. The session's own client must send the ping, because a separate client leaves the ADB tunnel to go offline. The option is off by default so instance lifetime is unchanged unless requested.
@thymikee

thymikee commented Oct 3, 2026

Copy link
Copy Markdown
Member

The PR is ready at 77b62f4. I found no problems in the diff.

Not blocking: startKeepAlive in https://github.com/callstack/agent-device/blob/77b62f4/packages/provider-limrun/src/runtime.ts#L391 sets the timer for a lease without clearing one already stored, so two concurrent allocate calls for one lease can orphan the first timer. This is the same existing race that already orphans the first session. Allowing at most one timer per lease, ideally by sharing one in-flight allocate per lease, would close both leaks, and you can take it or leave it.

The Coverage check fails only in the eager-closure budget test. The extra module comes from the instance-access.ts import at runtime.ts:56, which the base PR #3173 adds and this diff does not touch. Please land or fix #3173 first, then rebase this PR so the check runs against a merge-base that includes that import. No conflicts.

The live Limrun runs in the description (the session timing out without the flag, staying ready with it, and snapshot -i after 240 s idle) are the author's claim, and I did not see a transcript. They used attached instances only, so the created-instance route has not been run live.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 3, 2026
@thymikee
thymikee marked this pull request as ready for review October 4, 2026 05:45
@thymikee
thymikee merged commit d1694fe into callstack:claude/limrun-scoped-token-attach-c41aff Oct 4, 2026
14 of 15 checks passed
thymikee added a commit that referenced this pull request Oct 4, 2026
…3173)

* feat(limrun): drive an existing instance with its own URL and token

Read the lim CLI instance variables (LIM_IOS_INSTANCE_URL/TOKEN,
LIM_ANDROID_INSTANCE_URL/TOKEN/ADB_URL). A platform with instance access
attaches to that instance without LIMRUN_API_KEY and never creates or
deletes it. Operations that need the organization API (apps, install,
expired-lease recovery) fail with UNSUPPORTED_OPERATION when no key is set.

* fix(limrun): keep the owner's state on attached instances

Address review on #3173: attached Android teardown removes only the port
reverse mappings this session created; app-log reconnect routes by the
descriptor's instance id, so a created instance still reattaches through the
organization API while another instance is attached; the attached reconnect
honors its abort signal; the Android verification hint names the ADB URL
variable; connect tests unstub env between tests.

* refactor(limrun): simplify instance attach wiring

Build attached sessions in the runtime from the existing session
constructors instead of two near-identical allocation helpers, fold the
attached URLs into the runtime fingerprint directly, merge the attached
verification connector, and derive the connect error from the one list of
instance variables.

* fix(limrun): keep daemon boot independent of Limrun attach config

A partial LIM_* instance set no longer stops the daemon: composition skips
the Limrun runtime, reports it, and the daemon logs provider_runtime_skipped
while every other provider loads. CLI connect still fails fast.

Sessions and app-log descriptors carry a typed ownership ('created' or
'attached') instead of an attached- id prefix check; descriptors persisted
before the field decode as created. The attached id helper moves into
device.ts, so the provider entry evaluates no extra module. Expired-lease
recovery is guarded on the API key, the connect message states its daemon
condition, and the runtime test resets runCmd between tests.

* fix(daemon): log skipped provider runtimes after publishing daemon info

publishDaemonInfo truncates daemon.log, and before publication the daemon
does not own the state directory, so the provider_runtime_skipped
diagnostic now follows the startup diagnostics flush.

* test(daemon): shut the skipped-provider startup runtime down in finally

* feat(limrun): keep idle sessions alive with LIMRUN_KEEP_ALIVE (#3185)

Limrun ends an instance after its inactivity timeout, which idle sessions hit while a model thinks between steps. The session's own client must send the ping, because a separate client leaves the ADB tunnel to go offline. The option is off by default so instance lifetime is unchanged unless requested.

---------

Co-authored-by: Jakub Romańczyk <lorczyslav@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants