Repository navigation
Retire Squadrons and fold their J5 behavior into projects (decided) #412
Description
Status: decided on 2026-10-05. Squadrons are being retired. The text below is the original proposal, kept as written. Current status and what other users need to do are in this comment.
The question
Should J5 retire the Squadron as a concept separate from upstream's project, and attach the J5 behavior that hangs off Squadrons (the A2A ledger, Exchanges, placement, Crews, the Fleet page) to projects instead?
Why this came up
A new-thread UX question (the Squadron picker opening before every new thread) kept turning into a question about the Squadron itself. The Squadron was meant to work like an epic that spans several folders, which doesn't fit upstream's one-folder-one-project model. Multi-folder support was deferred, and so far there's no need for it. Meanwhile, keeping the Squadron mechanically separate from (though built on) projects has real costs:
- Settings. Projects are hidden everywhere except settings, so the person meets a noun there that the rest of the app never shows them.
- Shared projects. Two Squadrons can reference one project. That is a class of bugs upstream's model doesn't have, and a case no one uses.
- Fork cost. 19 of the 58 cases in
FORK.mdtouch Squadrons, including the largest new-thread seams (16, 19). Four entries in the register of divergences (D8–D11) exist only because a Squadron isn't a project. D11 is why scheduled tasks created in the UI can't start threads. - Open work. Around 15 open issues exist only because of the split (listed below).
The use case the Squadron was built for, several separate efforts on one repository, can already be covered inside one project by separate sets of agents and Crews. It isn't clear we'd outgrow that.
What we found
Measured against one live install, read-only:
- Every Squadron references exactly one project. No project is shared by two Squadrons. No thread sits in a project its Squadron doesn't reference.
- About half the live threads have no Squadron home. That looked like a bug, but isn't:
- 110 are provider-native Subagents (Codex and Claude workers, plus one
delegate_taskchild). By definition they aren't participants and get no home. - 5 were created from the mobile app, which has no Squadron surface yet (fix(mobile): replace project-first creation with Squadron creation and selection #128). Those are the only user-created threads without a home.
- 110 are provider-native Subagents (Codex and Claude workers, plus one
Measured against upstream (our pin 67a2be0 and current main 6414268):
- Upstream allows one active project per folder. Retiring Squadrons loses "two separate efforts over one repository, each with its own name." Today that only exists as an unused capability.
- A thread's project is fixed when the thread is created.
projectIdis set only bythread.create;thread.metadata.updatecan't change it. Drafts can change project before their first send, client-side only. So the Registrar's rule that "a home never changes" maps directly onto a thread's project.
Upstream now has threads without a project
Upstream merged these after our pin, so they arrive with the next upstream advance:
- No project (feat: start threads without a project pingdotgg/t3code#13612, 2026-09-30). A thread can start with "No project".
- It is still a project: each environment gets one "No project" project (
projects.ensureScratch), and each of its threads gets its own folder under<home>/scratch/. So the rule that a thread's project is fixed at creation still holds. - Ways in: the draft heading's project menu, the palette's New thread in... list (which the sidebar "+" still opens), a palette action, a
mod+alt+nhotkey, the no-projects screen, and mobile. - Moving out: a no-project draft reads "What should we work on?" and can be moved into a project before it is sent.
- It is still a project: each environment gets one "No project" project (
- New project from just a name (feat: start a new project from just a name pingdotgg/t3code#14527, 2026-10-01). The server creates
<home>/projects/<slug>with a README, an icon and a first commit, then opens a thread there. - Mobile gets a No project row at the top of its project picker (fix(mobile): one No project row at the top of the project picker pingdotgg/t3code#14532).
Why this matters for the proposal:
-
Another reason to fold.
- Under projects, these features arrive as upstream built them.
- Under Squadrons, every no-project thread needs a Squadron home, or send refuses. Supporting it means one of three things, each new fork work:
- an automatic Squadron for the "No project" project, which the Squadron definition forbids (no default "junk drawer");
- letting these threads go without a home, which leaves them out of the ledger and every Squadron filter;
- hiding the feature.
-
It lands on Squadron seams. The PR rewrites:
DraftHeroHeadline, which J5 replaces wholesale (D8);- the palette's New thread in... list;
- the new-thread shortcuts in
_chat.tsx; - the no-projects screen;
- mobile's new-task picker.
The next advance conflicts on all of them either way. Under Squadrons, each one also has to be converted again.
-
It closes a gap D9 records. Requiring a folder rules out non-coding work. "No project" and name-only projects cover that upstream.
-
Upstream keeps the picker on "+". The new-thread friction that started this discussion is upstream's too.
If we fold, things to decide about no-project threads:
- Accept upstream's default container? "No project" is the unnamed default the Squadron definition rejected as a junk drawer. It's probably fine, since upstream aims it at throwaway work, but it reverses a recorded decision and should be named as one.
- One shared partition. All no-project threads on an environment share one project. That means one ledger partition and one Fleet group. Under upstream's same-project rule, agents in unrelated scratch threads could also archive each other or merge back.
- Peer Agents and Crews started from a scratch thread. They would land in "No project". Whether they share the parent's folder or get their own depends on what
spawn_agentpasses (see spawn_agent puts every Peer Agent in the caller's branch and worktree #274). Not yet checked. - Hidden in J5 dev servers. Upstream withholds the feature when the home is inside a Git checkout, which is the case for a worktree's
.j5code. Testing it needs a home outside a checkout.
What the change would be
- Projects become the unit the person picks, filters by, and organizes around, as they are upstream. The J5 UI built for Squadrons goes back to upstream's project UI:
- Create Squadron
- the first-run Squadron gate
- the welcome wizard's Squadron stage
- the sidebar Squadron scope
- the Squadron picker, draft chip and headline
- the Squadron label on thread cards
- J5 features re-key from Squadron to project:
- the A2A ledger, Exchanges and the placement tree
- Crews
- the Fleet page
- Peer Agents inheriting their spawner's home, which already lands them in the spawner's project
- Agent-to-agent communication stays unbounded. "Never a boundary on communication" still holds; nothing about it depends on the Squadron.
- Archive and merge-back checks collapse into upstream's existing same-project rule.
- Removed:
list_squadronsandjoin_squadron. Every thread already has a project. - Docs: the Squadron product definition is retired. The glossary, overview and register entries D8–D11 are rewritten. The FORK cases that exist only for Squadrons are removed as their code goes.
Lost:
- Multi-folder Squadrons (Squadrons can target more than one folder #356).
- Several named efforts over one folder.
- The Squadron name as a fleet-native noun. Keeping "Squadron" as a UI label on projects would keep paying the fork cost D8 justified only by the many-to-many shape.
Migration (has to work for every live install)
J5 is live for more than one person, so this would need a migration that runs on each environment's server against data we can't see. Cases it would need a rule for:
- One Squadron, one project. The normal case: the Squadron's ledger, memberships, placement and Crews move to the project.
- Several Squadrons on one project. Merge their ledgers into the project, refuse to migrate, or something else? Their names would be lost or need a home.
- One Squadron with several projects. The UI caps creation at one folder, but the server's create path accepts a list.
- A Squadron whose project was deleted.
- A Squadron name that differs from its project's title. Keep the project title, or offer to rename the project?
- Threads with no home (mobile-created, the startup auto-bootstrap thread in Web-mode auto-bootstrap creates a Squadron-less project thread at startup #287). Backfill ledger membership, or register on first A2A use?
- Mixed versions. Clients read Squadrons from every connected environment (the
j5Squadronscapability). The mobile app ships separately and can talk to servers on different versions. - One-way. As with the V2 database cutover, it should be safe to snapshot before and roll back by restoring the snapshot.
Open questions
- Is "several efforts on one repository" something we want to keep supporting, by some means other than Squadrons?
- Should the ledger re-key to project ids, or keep a hidden one-to-one partition per project? Re-keying is cleaner. A hidden partition is a smaller migration, but keeps the separation this proposal is trying to remove.
- What should the migration do with shared-project and multi-project Squadrons on other installs?
- Do any other installs actually have shared-project Squadrons? Knowing that would settle question 3.
- If we keep Squadrons, how should upstream's no-project threads get a home? If we fold, do we accept "No project" as upstream ships it?
Issues this would close or reframe
- Close, because the split goes away: Squadrons can target more than one folder #356, A person can give a thread with no home its Squadron #358, Creating an agent in a Squadron can still reach folders outside it #357, Decide a Squadron's end of life: archive, or delete only #362, Scheduled tasks: decide how schedules bind to a Squadron #273, E7 follow-up — scheduling-context Squadron selector (board #146) #38, Reloading a draft loses its chosen Squadron #295, feat(web): clarify cross-environment Squadron selection for existing drafts #154, test(web): cover Squadron selection after draft auto-balancing #139, E7 follow-up — LegacySidebar new-thread door conversion (board #148) #39, feat(j5): integrate agent project mutations with Squadron ownership #134, fix(j5): reconcile archive racing an existing thread’s first Squadron assignment #179, fix(mobile): replace project-first creation with Squadron creation and selection #128 (in its current form), Squadron creation dialogs render the folder picker at two sizes; form width is cramped #48, Web-mode auto-bootstrap creates a Squadron-less project thread at startup #287
- Reframe from Squadron to project: Scope t3_pending_request_respond to the caller's Squadron, or hide it from agents #345, Fleet page: show each project's cost and each agent's share #361, Fleet page: measure the four facts, problems and badge as defined #360, Homed agents should be told their own participant id and Squadron, not only spawned ones #199, feat(mobile): J5 daily-use parity — Squadrons, inbox, A2A, and lifecycle #40, refactor(j5): move Squadron and inbox routes to a typed HttpApiGroup #137
The new-thread picker change that started this is parked until this is decided. If projects come back, the friction becomes upstream's own (the picker opens when there is more than one project), and any change to it would be a much smaller divergence.
🤖 Generated with Claude Code
Activity
Jacksondr5 commentedon Oct 3, 2026
Tracking: #328 (forced Squadron delete) is held open pending this decision. If Squadrons are retired, close #328 without merging, since upstream's forced project delete covers it. #362 (a Squadron's end of life) is answered by the same decision.
Posted by an AI agent on Jackson's behalf
Jacksondr5 commentedon Oct 8, 2026
Decided: Squadrons are being retired and their behavior folded into projects (Jackson, 2026-10-05). No install is known to have two Squadrons on one folder. The work is under way.
Where it stands (2026-10-08)
Still to come
list_squadronsandjoin_squadronare removed. Other tools stop taking or returning Squadron ids.j5 a2acommand line.AGENTS.mdand the marketing site are rewritten.What other users need to know
Update everything together when the migration ships. After it, a client, desktop app or peer server on an older version refuses to work and shows an "update" message. Nothing is silently wrong, but mixed versions do not work.
The server takes a snapshot of its database before the migration runs, beside the database as
statev2.pre-j5-<migration number>.sqlite. The restore steps are indocs/j5/runbooks/dogfood-runtime.md.If you ever had two Squadrons on one folder, the migration refuses to run and says so by name. To check now, read-only:
No rows means you are fine.
Decisions from the open questions above
Follow-ups
Posted by an AI agent on Jackson's behalf.
[-]Proposal: retire Squadrons and fold their J5 behavior into projects[/-][+]Retire Squadrons and fold their J5 behavior into projects (decided)[/+]feat(a2a): a thread's home is its project
docs(marketing): the site no longer advertises Squadrons (#477)
feat(a2a): a thread's home is its project (#482)
refactor(web): plan implementation goes back to upstream's create-the…
refactor(a2a): internal names say project (#484)
feat(a2a): the peer wire says project (#489)
Jacksondr5 commentedon Oct 8, 2026
Done. The fold is merged to
j5/main: #423, #428, #429, #430, #431, #454, #455, #456, #457, #482 (migration 031), #483, #484 and #489 (peer wire, protocol version 2), plus the site in #477. The docs are in draft at #488. The follow-up check that the word is gone is #476.Upgrading: a server writes
statev2.pre-j5-031.sqlitebeside its database before the migration runs. Update the server, desktop app, mobile app and browser tabs together, and update peered servers together. A project that several Squadrons shared stops the server at start-up and names the project; none is known.