Summary
After /clear, every swarm tool action that needs membership (spawn, list, start, …) fails with:
Not in a swarm. Use a git repository to enable swarm features.
The message points at git, but the repo is a valid git worktree (git rev-parse --is-inside-work-tree → true) and features.swarm = true. The actual cause is that the session created by /clear is never registered as a SwarmMember.
Version: v0.75.0 (5ae2385), Windows x86_64.
Root cause
In crates/jcode-app-core/src/server/client_session.rs, handle_clear_session:
- Removes the old session's member entry (intentional, per the comment "Do not migrate the old session's swarm membership"):
let swarm_id_for_update = {
let mut members = swarm_members.write().await;
members.remove(client_session_id).and_then(|member| member.swarm_id)
};
- Then calls
update_member_status(&new_id, "ready", …) — but update_member_status_with_report_tldr (swarm.rs) only does members.get_mut(session_id) and silently no-ops in the else branch when the member does not exist. It never inserts.
- The only function that creates a member,
ensure_client_swarm_member, is called exclusively from handle_subscribe. /clear never re-runs it, and the connection stays subscribed, so no new subscribe happens.
- The
clear_done log then reports swarm_id_updated=true, which is misleading: it only means the old member had a swarm id to remove, not that the new session was registered.
Result: the new session has no SwarmMember entry, so every swarm_id_for_session(id) → members.get(id).and_then(|m| m.swarm_id) returns None, and all comm handlers answer "Not in a swarm."
Evidence (from ~/.jcode/logs/jcode-2026-08-10.log)
17:43:37 EVENT event=SESSION_LIFECYCLE … phase=clear_done old_session_id=session_guppy_… new_session_id=session_skunk_… swarm_id_updated=true
17:45:00 EVENT event=TOOL_LIFECYCLE … error="Not in a swarm." (swarm spawn)
17:45:08 EVENT event=TOOL_LIFECYCLE … error="Not in a swarm. Use a git repository to enable swarm features." (swarm list)
Every phase=swarm_member_registered event of the day belongs to sessions that went through handle_subscribe; none names the /clear-born session. Its state file ~/.jcode/state/swarm/session_session_skunk_….json does not exist.
Checked 5ae238574..origin/master on client_session.rs: no later commit fixes this. #816's fix (reset swarm plan state on clear, 5496ebb) is an ancestor of v0.75.0 and doesn't cover member re-registration.
Repro
- Open a jcode TUI session in a git repo, use any
swarm action (works).
/clear.
swarm list → "Not in a swarm. Use a git repository to enable swarm features."
Workaround: quitting the client and jcode resume on the same session re-registers the member via handle_subscribe.
Suggested fix
In handle_clear_session, after swapping in the fresh agent and before update_member_status, re-register the replacement session, e.g. call ensure_client_swarm_member(&new_id, client_connection_id, …, swarm_enabled, …) (the old member's swarm_enabled can be captured before the remove). Alternatively, make the update_member_status no-op branch log a warning so the next silent drop of this kind is visible.
Also worth a tweak: the "Use a git repository to enable swarm features" wording sends users debugging git/config when membership is the actual gate.
Summary
After
/clear, everyswarmtool action that needs membership (spawn,list,start, …) fails with:The message points at git, but the repo is a valid git worktree (
git rev-parse --is-inside-work-tree→true) andfeatures.swarm = true. The actual cause is that the session created by/clearis never registered as aSwarmMember.Version: v0.75.0 (5ae2385), Windows x86_64.
Root cause
In
crates/jcode-app-core/src/server/client_session.rs,handle_clear_session:update_member_status(&new_id, "ready", …)— butupdate_member_status_with_report_tldr(swarm.rs) only doesmembers.get_mut(session_id)and silently no-ops in theelsebranch when the member does not exist. It never inserts.ensure_client_swarm_member, is called exclusively fromhandle_subscribe./clearnever re-runs it, and the connection stays subscribed, so no new subscribe happens.clear_donelog then reportsswarm_id_updated=true, which is misleading: it only means the old member had a swarm id to remove, not that the new session was registered.Result: the new session has no
SwarmMemberentry, so everyswarm_id_for_session(id)→members.get(id).and_then(|m| m.swarm_id)returnsNone, and all comm handlers answer "Not in a swarm."Evidence (from
~/.jcode/logs/jcode-2026-08-10.log)Every
phase=swarm_member_registeredevent of the day belongs to sessions that went throughhandle_subscribe; none names the/clear-born session. Its state file~/.jcode/state/swarm/session_session_skunk_….jsondoes not exist.Checked
5ae238574..origin/masteronclient_session.rs: no later commit fixes this. #816's fix (reset swarm plan state on clear, 5496ebb) is an ancestor of v0.75.0 and doesn't cover member re-registration.Repro
swarmaction (works)./clear.swarm list→ "Not in a swarm. Use a git repository to enable swarm features."Workaround: quitting the client and
jcode resumeon the same session re-registers the member viahandle_subscribe.Suggested fix
In
handle_clear_session, after swapping in the fresh agent and beforeupdate_member_status, re-register the replacement session, e.g. callensure_client_swarm_member(&new_id, client_connection_id, …, swarm_enabled, …)(the old member'sswarm_enabledcan be captured before theremove). Alternatively, make theupdate_member_statusno-op branch log a warning so the next silent drop of this kind is visible.Also worth a tweak: the "Use a git repository to enable swarm features" wording sends users debugging git/config when membership is the actual gate.