Skip to content

Chats without a project: a built-in Chats container with one scratch folder per chat - #887

Open
danyaberezun wants to merge 22 commits into
global-search-startfrom
global-search-chats
Open

danyaberezun wants to merge 22 commits into
global-search-startfrom
global-search-chats

Conversation

@danyaberezun

@danyaberezun danyaberezun commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Every chat in ThinkRail belongs to a workspace, and every workspace to a git repository. There is no place for the question that has no repo yet — "compare these two caching strategies", "draft the launch checklist" — except to open some project and pollute a worktree with it. The 2026 agent apps all have this surface (Codex ⌥Space and ⌘⌥O, Claude Quick Entry, T3's projectless threads); the global-search interview (#804's research) put it on the roadmap as the palette's one missing start target, and the user kept it in the plan after the redesign.

Fourth PR of the global-search stack; stacked on #806. Design and review history: TASK-projectless-chat.md (three design-review rounds, "Ready to implement").

Rebased on main (Oct 26, then twice on Oct 28) with the stack. CHATS_PROTOCOL_VERSION is now v97 (main holds v95 for #975's repository cloning; search is v96). The Oct 26 commit fix(web): label an unnamed chat without a project by its first prompt in Chats, the topbar and its empty center brings #911's first-prompt label to this PR's surfaces. main's #975 clone and #808 first-run wizard meet this PR: the Chats root is refused by clone too, and the container no longer hides the wizard (below).

Review (Oct 28). Two design reviews and three code-review rounds (GPT-6 Astra / GPT-6.1 Sol, Claude Fable 5.1) confirmed all 11 open review-bot threads and found more; the fixes:

  • One lifecycle per chat. Start, recovery and deletion share one per-chat claim; a recovery joins a start in flight, and a delete closes the workspace's session admission through the agent's own barrier (closeWorkspaceSessions, which archive's teardown now uses too) before it lists anything, so a delete during the first session's start or two concurrent recoveries can no longer leave an orphan session or a second conversation. A chat being deleted or with its deletion pending is refused at every resource door (CHAT_DELETING, CHAT_DELETION_PENDING); a second session is CHAT_HAS_SESSION, the one code New chat turns into a sibling chat. An Agent child's transcripts go to the Trash with the chat.
  • Older clients see nothing of chats — not in search, previews, history, the container's lists, extension UI (also while a session is still starting) or a detached session's rename.
  • The Chats root is reserved canonically (lexically and through the nearest existing ancestor's real path) at every project door: inspect, open, init, create, clone destination, clone (before anything downloads) and attaching an existing worktree.
  • No git, review or specs in a chat: the file list keeps its no-git mode through every refresh, Files skips the git-ignore check, /blob refuses a chat, Agent review and its tool never reach a chat's session, plan review is refused, and search returns no chat workspace hits and no specs for a chat root; the web hides Settle and the automatic Settled shelf, per-session Trash, Manage skills, file commenting, plan review and the palette's Specs scope there.
  • The first-run wizard is back on a fresh install: the onboarding selectors count repository projects only (the host ensures the container at boot), and a first chat ends the wizard. The e2e reset used to delete chats.json under the running host, which hid this; it now keeps the boot-created container, so e2e cold starts are a user's.
  • Web: one target-bound delete confirmation (rail and topbar) that closes when its chat goes or starts deleting elsewhere; a reconnect reconciles the Chats membership (replaceProjectMembership), so a chat deleted while away leaves; the topbar's Chats loads the list before it starts a chat; the Create dialog keeps its draft when another window opens or reorders projects; a double click starts one chat; no surface opens a chat pending deletion; host hits and the topbar name chats and the container by their labels.
  • Robustness: chats.json is schema-checked — an invalid v1 file is set aside, a newer version or an unreadable file is left untouched and writes are refused, and the parsed store is cached by file identity; chat.inspect walks asynchronously within entry and time budgets.

Approach

  • One container, one folder per chat, kind is the marker. A built-in Chats project (Project.kind: "chats", root ~/.thinkrail/chats, permanently untrusted, never closed) holds one kind: "chat" workspace per chat, each its own folder <yyyy-mm-dd>-<short id> (no words from the prompt — architecture Decision 8 stands). Records keep the required wire fields with inert values (branch: "", baseBranch: ""), so the ≈80 branch/baseBranch reads and every workspace-keyed module (fs, terminal, watch, plan, search) work unchanged; routes, store keying and navigation restore are unchanged. Rejected: a separate entity, an optional projectId.
  • Held apart for rollback. chats.json (PersistedChats v1, atomic) is merged on load and partitioned on save by kind for both legacy files, so an older host — the CLI is the supported rollback artifact — never sees a chat and its reclaim path can never rm -rf a chat folder. An invalid file is set aside (.corrupt-<epoch>); a newer version or an unreadable file is left untouched, and chat writes are refused meanwhile.
  • Never git. Explicit capability narrowing at every door before any git work: REPOSITORY_ONLY_METHODS (git, changes, reviews, PRs, turns, diff stats/base) refuse a chat at the handler; project close/rename/trust/skills, workspace.create/listExisting, git.listBranches/prefetch refuse the container; the settled lifecycle, turn snapshots, plan artifacts, head recording, diff stats and the external refresh skip chats; project.open/init refuse paths under the chats root; search walks a chat folder instead of git ls-files. Plus a boot-time GIT_CEILING_DIRECTORIES=<dataDir>/chats so git, gh, PTYs and pi's bash inherit a ceiling that stops any walk up out of a chat folder into a repository that happens to enclose the data dir (~/.thinkrail inside a checkout). A unit test records every Bun.spawn/spawnSync across create / list / doors / delete and asserts no git under the chats root, and runs real git rev-parse from a chat folder nested inside a real repo expecting failure.
  • The only doors are the chat methods. chat.create makes folder, record, initial terminal and the one session the chat owns in one call (host default model or the dialog's pick); session.create on a chat that already has one is refused (CHAT_HAS_SESSION) — a second conversation is a new chat — and otherwise heals a chat whose session never started (joining a start still in flight). chat.delete is the single teardown: claim → mark deletionPending (persisted before anything destructive, survives restart with Retry) → every session through the agent's trash-based transaction (transcripts file by file, never the encoded directory) → terminals, watcher, sidecars → trash the folder → drop the record → publish removal; session.delete on a chat is refused. chat.inspect gives the confirmation its bounded file count. The host never sweeps unknown folders under the chats root.
  • Older clients. Sockets below CHATS_PROTOCOL_VERSION (v97) get a welcome, project.list and session.stateList without the container, its chats and their records, and every id-carrying push goes through one publishScoped sender (per-socket for a chat/container id, broadcast otherwise). The chat-id check is answered from memory (only this process writes the store), so pi.event pays no file read.
  • Titles on the wire. SessionStateRecord.title exposes pi's session name (never copied); the publication fingerprint includes it and the disk-only rename path republishes — the Chats rows, the topbar and the palette read titles from state records.
  • UI. A Chats section tops the Projects panel (rows by recency with title, status dot, Delete with the file count; "Deletion incomplete" → Retry); the topbar reads Chats › <title> with no branch or ship strip; the Create dialog gains a Chat without a project target — the only one when no repository is open — and the Welcome a card for it; the palette offers "New chat without a project" and its start row works with no repository; git- and spec-backed tool bodies say "Not available in a chat without a project" while Files, terminal and Plan work; New chat inside a chat starts a sibling chat. Repository listings and fallbacks read selectRepoProjects, so the container is never offered as a project. The Chats section and start surfaces gate on protocol support alone; the host ensures the container at boot, and it never counts as a project — not for the first-run wizard either.

Deferred (named in the task-spec): per-step crash-point tests of the delete transaction (covered end to end with a trash seam); pi-subagents' cosmetic "Git branch:" line under the ceiling; Continue in workspace (PR5, with the continuedTo marker).

Changes

  • packages/contracts: PROTOCOL_VERSION = 97 = CHATS_PROTOCOL_VERSION; Project.kind?: "chats", Workspace.kind gains "chat", Workspace.deletionPending, SessionStateRecord.title; chat.create / chat.delete / chat.inspect (ChatCreateResult, ChatInspection); error codes CHATS_CONTAINER, CHAT_WORKSPACE, NOT_A_CHAT, CHATS_STORE_UNAVAILABLE, and from the review CHAT_HAS_SESSION, CHAT_DELETING, CHAT_DELETION_PENDING.
  • packages/server: persistence (chats.json, partition on save, set-aside, chatsRoot), workspaces/chats.ts (container, records, id cache, refusal helpers) + gates in workspaces.ts, host/chats.ts (create/ensure/inspect/delete), host/gitCeiling.ts, handlers (doors, filtering, REPOSITORY_ONLY_METHODS), server.ts (publishScoped, boot container, welcome filtering), settledLifecycle/turns/todos/search/analytics gates, agentSessionManager titles, spec.specSnapshot unchanged API. Tests: persistence/chats.test.ts, host/chats.test.ts (+ boot/channel/search test updates).
  • apps/web: store selectors (selectRepoProjects, selectChatsContainer, selectChatWorkspaces, selectChatWorkspaceTitle, selectContextRepoProject, isChatWorkspace, supportsProjectlessChats), panels/chatActions.ts, panels/ChatsSection.tsx, NewWorkspaceDialog chat target (projectId: string | null), WelcomePanel card, openChat sibling fallback, FilesPanel/useGitStatus no git for chats, shell/locationBar/ChatSegment.tsx, ProjectSegment Chats entry, WorkspaceWorkbench unavailable bodies, Shell dialog context, palette command + start row; 23 locale keys.
  • Review fixes (Oct 28): host/chats.ts (per-chat claim, deletion inside the agent barrier, resource-door refusals, async budgeted inspect), agent (closeWorkspaceSessions, trashWorkspaceDelegation, getSessionAttribution), visibility in search / historyScope / handlers / server.ts, persistence (landsInChatsRoot, validated and cached chats.json), projects / clone / workspaces (assertOutsideChatsRoot), search/files.ts git mode, fileRoutes; web ChatDeleteDialog, onboarding selectors, replaceProjectMembership, kind-aware Settle / Trash / skills / commenting / plan review / Specs scope, dialog defaults per opening, joined start, pending filters, labels. Tests: host/chatsWire.test.ts (real v96/v97 sockets), lifecycle races and restart in host/chats.test.ts, persistence/search/projects cases, web store/selector/search cases.
  • e2e: chats.spec.ts (Welcome → chat with its own folder, no git tools, Files works; a double click starts one chat and a Delete confirmation closes when another window deletes its chat; palette → dialog chat target → first prompt → delete to Trash), welcome.spec.ts and onboarding.spec.ts expectations, resetState drops every chat but keeps the boot-created container.
  • Review pass (independent reviewer, approve + 4 non-blocking findings, all fixed in 687b8df78): the plan read skips the unattributed-change / adopted-commit git reads for a chat and the Plan page hides its branch line, commits menu and Open PR; the setup funnel's project_present ignores the container; a first chat loads the container's list instead of seeding it; the chats-store latch has a test seam.
  • Specs: architecture Decision 6, goal-and-requirements, contracts, server graph, workspaces, persistence, host, agent, trash, web panels, shell, locationBar, store, e2e; README bullet.

Screenshots

1280×800. Before = the stack's head (#806) with no project open; After = the same screen with the Chats section and the chat card, then the chat itself.

Before — Welcome with no project: Open project only After — Welcome offers "Chat without a project" beside Open project
The Welcome screen before: title, provider warning, a single Open project card and an empty Projects panel The Welcome screen with the Chats section (empty) at the top of Projects and a Chat without a project card
After — a chat without a project: Chats › Chat, its own folder in the terminal, Specs and Review not available After — the Create dialog's "Chat without a project" target from the palette's typed text
A chat without a project: topbar Chats › Chat, the Chats section with one active row, terminal in the chat's dated folder, Specs and Review panes reading Not available in a chat without a project The New chat without a project dialog: the third target selected, no project or branch picker, the typed prompt filled
After — Delete chat… names what moves to the Trash
The delete confirmation: the conversation and the chat's folder with its files move to the Trash

Testing

All on the final head (52a50c332) unless noted:

  • bun run lint, check:deps, check:boundaries, check:seams, check:i18n, check:spec-surface, check:compiler → green; bunx turbo run typecheck --filter='!@thinkrail/desktop' → 24/24
  • cd packages/server && bun test → 2063 pass, 4 skip, 0 fail; cd packages/contracts && bun test → 114 pass; apps/web bun test → 2055 pass
  • Each review fix's new test fails with its fix removed (lifecycle races, restart with a pending deletion, delegated transcripts in the Trash, mixed-version sockets incl. a session_start notice, reserved-root aliases, git-free reloads and fs.readDir, store version/shape/I-O handling, inspect budgets, onboarding with the container, settle, pending palette items, reconnect membership)
  • bun run e2e e2e/chats.spec.ts --repeat-each=3 → 9 passed; e2e/chats.spec.ts e2e/onboarding.spec.ts --repeat-each=2 → 40 passed
  • bun run e2e (full no-agent suite, 8 shards) → all passed (a first run lost e2e/extension-dialogs.spec.ts:178 once — a viewport timing check this PR does not touch — which then passed 25/25 under --repeat-each=5)

Related issues

Part of the global-search stack (#804 → #805 → #806 → this). Refs #765 (chat titles now ride the state record).

Checklist

  • Fast gates pass: bun run lint, bun run typecheck, bun run test
  • E2E suite passes for app-affecting changes (bun run e2e, or bun run e2e:full when touching agent behavior)
  • Before/after screenshots are included for frontend changes, or marked not applicable
  • Relevant SPEC.md / top-level specs updated to reflect any boundary, contract, or behavior change
  • I have read the Contributing guide and agree to the Code of Conduct

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes — please address the blocking inline findings.

Comment thread packages/server/src/host/chats.ts Outdated
Comment thread packages/server/src/host/handlers.ts Outdated
Comment thread packages/server/src/host/chats.ts Outdated

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes — please address the blocking inline findings.

Comment thread packages/server/src/host/chats.ts Outdated
Comment thread packages/server/src/host/handlers.ts
Comment thread packages/server/src/search/files.ts Outdated
Comment thread apps/web/src/panels/FilesPanel.tsx

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes — please address the blocking inline findings.

Comment thread packages/server/src/host/server.ts
Comment thread packages/server/src/host/handlers.ts
Comment thread packages/server/src/workspaces/workspaces.ts

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes — please address the blocking inline findings.

Comment thread packages/server/src/host/chats.ts Outdated
A kind:"chats" container rooted at <dataDir>/chats and one kind:"chat"
workspace per chat, stored apart in chats.json (partitioned on save, merged
on load, set aside when corrupt) so an older host never sees them. New
wire methods chat.create (folder + record + the one session), chat.delete
(the only teardown door: transcripts and the folder go to the trash, the
record is marked pending first) and chat.inspect; every repository door
refuses a chat or the container; git never runs in a chat folder, backed
by GIT_CEILING_DIRECTORIES; sockets below CHATS_PROTOCOL_VERSION never
hear about chats; session state records carry pi's session title.
…Create dialog

A Chats section tops the Projects panel (one row per chat with its title,
status and a Delete that names the folder's file count); the topbar reads
Chats › <title> for a chat with no branch or ship strip; the Create
dialog gains a "Chat without a project" target (the only one when no
repository is open) and the Welcome a card for it; git- and spec-backed
tool bodies say "Not available in a chat without a project" while Files,
terminal and Plan keep working; repository listings and fallbacks go
through selectRepoProjects, and a second New chat in a chat starts another
chat.
Architecture Decision 6 gains the third kind-marked exception; goal
capabilities, the workspaces, persistence, host, agent, trash, contracts,
server-graph, panels, shell, location-bar, store and e2e specs describe
the container, the chats store, the refusal doors, the ceiling, the scoped
pushes, the titles on state records and the UI surfaces.
…nd load the Chats list on a first chat

Address the review: the plan read skips the unattributed-change and
adopted-commit git reads for a chat and the Plan page hides its branch
line, commits menu and Open PR; the setup funnel's project_present ignores
the Chats container; a first chat loads the container's list instead of
seeding it; the chats store latch has a test seam.
…s the Chats container

The host ensures the Chats container at boot, but the onboarding selectors counted every project, so a
fresh install with no repository and no provider never showed the setup wizard. Both selectors now count
repository projects only, the shown branch included, and the done step's cards now include Chat without
a project next to Open project.
… doors out of chats

The topbar's Delete chat confirmed whatever chat was active by then; one ChatDeleteDialog, shared with the
Chats row, now holds the chat it was opened for, names its file count, and closes when that chat is
removed, starts deleting elsewhere or stops being the active one. Settle and the automatic Settled shelf,
per-session Trash in Recently closed and prompt history, Manage skills in the chat target and file
commenting are no longer offered for a chat. A pending deletion is opened by no navigating surface; the
topbar's Chats loads the container's list before it starts a chat; a reconnect replaces the container's
membership; host hits name a chat and the container by their labels; a start in flight is joined, and a
first chat ends the first-run wizard; the Create dialog takes its defaults once per opening.
A delete during a chat's first session left a live session in a trashed
folder, two concurrent recoveries started two top-level sessions, and a
deletion-pending chat still attached sessions and spawned terminals
after a restart.

One per-chat claim now serializes create, first session, recovery and
delete: a recovery joins a start in flight (same session, real model and
effort), and a delete takes the claim over. The deletion runs its Trash
moves inside the agent's own preparation barrier, exported from the agent
barrel as closeWorkspaceSessions (archive's removeWorkspaceSessions now
composes it), so sessions are listed only once nothing can still start or
write one; the folder is trashed only when it lies under the chats root.
Every session/terminal start or attach door refuses a chat being deleted
or whose deletion is pending, and initial-terminal provisioning skips it.
The refusals get their own codes - CHAT_HAS_SESSION, CHAT_DELETING,
CHAT_DELETION_PENDING - so a client never mistakes "being deleted" for
"start a sibling chat". The misnamed recovery test now recovers.
Deleting a chat without a project left delegation/<workspaceId>/ and the
workspace's delegation service behind. The agent now owns a recoverable
twin of archive's removeWorkspaceDelegation: trashWorkspaceDelegation
moves the store to the Trash (never rmSync) and only then releases the
service. The chat deletion calls it inside the agent's barrier, after the
child cascades settled and the transcripts went to the Trash, so a failed
move leaves both for Retry.
…ecovery

chat.create never recorded an explicit model as recent, its chat_started
reported the session's model even when the host found none to resolve,
and a chat's recovery through session.create dropped the requested model
and effort. Both creation paths now share one bookkeeping (noteNewChat:
an explicit pick becomes recent, analytics hear the model the chat got or
none), and the recovery passes the request through.
… pushes

A client below CHATS_PROTOCOL_VERSION still got chat workspace ids, the
container and chat transcripts from search.query, search.preview and
history.search, could list the container's or a chat's rows directly,
heard pi.extensionUi for chat sessions, and heard a detached session's
disk-only rename because its pi.event carried only a session id.

One visibility policy, seesChats(protocolVersion), now lives in
host/chats.ts and drives all of it: the search service takes the
client's audience and drops the container (and so its chats' records,
root, files, plans, titles, transcripts and previews) before any
provider ranks or pages; history.search hides chat cwds from every scope
through a hidden-cwd predicate; workspace.list of the container answers
[] and session.list of a chat answers as unknown; extension UI for a chat
session reaches only sockets that see chats and fall within the
request's own audience. The agent now hands every pi.event publication
its workspace beside the payload, so publishScoped scopes a detached
session's rename like a live one's. Tests cover a v96 and a v97 client
over the handlers, the search service, the history scope and real sockets.
project.cloneDestination and project.clone accepted the Chats root (the
clone downloaded, then openProject refused and stranded the checkout),
project.inspect offered init for a folder init refuses, and the
containment check was lexical, so /tmp versus /private/tmp, a symlink or
a folder that does not exist yet slipped past it.

One policy now guards inspect, open, init, create, the clone destination
(and so clone, before it reserves a folder or Git downloads anything) and
the existing-worktree admission: the projects barrel's
assertOutsideChatsRoot, over persistence's landsInChatsRoot - the lexical
check plus canonical containment through the nearest existing ancestors
of the path and of the root. It throws CHATS_CONTAINER before any
filesystem or Git side effect; a worktree registered under the root is no
longer offered either. Recorded paths keep their resolved spelling.
A chat without a project is files, terminal and Plan - never git, review
or specs - but several reused paths still treated it as a repository:
the search file cache reloaded a stale chat root through git, fs.readDir
ran git check-ignore for every listing, the /blob route ran git for a
chat id, request_review and its guideline were offered to chat sessions
whenever Agent review was on, the plan's review doors could reach a
git-backed review snapshot, and host search returned chat records as
workspace hits named "Chat" and answered specs for a chat root.

The file-list cache now keeps each root's git mode through every TTL or
invalidation reload; fs.readDir skips the git-ignore decoration for a
chat; /blob answers 404 for a chat before any git; the host's Agent
review resolver answers false for a chat, so its sessions get neither the
tool nor its guidance; todo.review/startReview/reviewAll/requestFix join
the repository-only doors; search leaves chat records out of workspace
hits and answers an empty spec group for a chat root while its files,
transcripts and plans stay searchable.
… store untouched

The chats store accepted structurally invalid JSON (a container without
an id later threw inside slugify), yet treated any non-ENOENT read error
- a transient EBUSY or EPERM - as corruption, renamed the file aside and
latched chat writes off; a newer host's store would have been set aside
the same way.

chats.json is now schema-validated: only a file that is not JSON, or is
not a valid version-1 store and names no newer version, is set aside. A
store with a newer integer version is left untouched, loads empty and
refuses writes; any other read failure renames nothing, is not
remembered and is read again on the next load. chatsStoreProblem names
which, and workspaces words CHATS_STORE_UNAVAILABLE after it. The parsed
store is cached while the file keeps the inode, size and mtime it was
read or written at, every load hands out a copy, and a partitioning save
builds only on that cached store, so a save after a failed load cannot
overwrite the chats the load missed.
…e budgets

chat.inspect walked the folder synchronously and capped only files, so a
directory-heavy scratch tree could stall the in-process host, and it
counted ThinkRail's own .thinkrail/context/.gitignore (an empty chat said
"1 file").

The inspection is now an asynchronous opendir walk that yields to the
event loop, bounded by CHAT_INSPECT_BUDGET - entries visited, folders
included, and wall time - and answers truncated when either runs out.
Symlinks are counted, never followed, and the scratch-dir scaffolding is
not counted.
…chat that already has one

A second conversation in a chat is now refused with CHAT_HAS_SESSION, so that code alone turns New chat
into a sibling chat; a chat being deleted or with its deletion pending is reported, never answered with
a new chat. The Plan page offers no review in a chat and the palette no Specs scope, matching what the
host now refuses and answers there.
…fresh install has it

resetState deleted chats.json under a running host, so every e2e cold start lacked the container that
production always has at boot, and the onboarding regression it caused stayed invisible. The reset now
drops the chats and their folders but keeps the container record and an empty chats root.
…still starting

The extension-UI publisher found a session's workspace only among registered sessions, so a notice an
extension or MCP startup sent during session_start, before registration, was broadcast to clients that do
not see chats. The agent now attributes a preparing session too (getSessionAttribution), and the
publisher scopes by it.
The walk checked its deadline only per entry, so a tree of many empty folders ran past the budget and
still answered truncated: false.
…nfirmation

A double click on Welcome's Chat without a project sends one chat.create, and a topbar Delete confirmation
opened for a chat closes when another window deletes that chat, so it can never delete the chat the
window falls back to.
…nding chats out of the palette

The reconnect refresh replaced the Chats container's list but left an active or open chat that another
window had deleted mounted with no row behind it; each chat gone from the list now goes through
applyWorkspaceRemoved first, as the missed workspace.removed push would have. The palette's work items
skip a chat whose deletion is pending, like every other navigating surface.
@danyaberezun

Copy link
Copy Markdown
Collaborator Author

@jetbrains-air please review — rebased with the stack onto main 7b07d5c5f (chats are protocol v97 now), plus 16 review-round commits (f382df700..52a50c332) that fix all eleven of your threads and the design/code reviews' further findings: one per-chat lifecycle claim with deletion inside the agent's barrier and refusals at every resource door; older clients see nothing of chats in search, history, lists or extension UI (also during session start); the Chats root reserved canonically at every project door incl. clone; no git, review or specs in a chat; a validated, cached chats.json; budgeted async inspect; the first-run wizard restored with the boot-created container (and the e2e reset now keeps it); a target-bound delete confirmation, reconnect membership, kind-aware controls, stable Create-dialog drafts and a joined start on the web side.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant