Repository navigation
Threads: several conversations per folder, subagents, project brief - #22
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Relative paths in the file tools resolve against the cwd DispatchTool is given, and bash chdir()s into it in the forked child (lpCurrentDirectory on Windows), so tools no longer depend on the process cwd. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ChatFrame's per-conversation state moves into a plain struct Thread held
in a std::deque; the existing functions take Thread&. Async callbacks
capture (thread id, gen) and drop stale results. Only the active thread
draws to the canvas; switching rebuilds it from history plus the
in-flight partial reply. One running turn per folder: a second thread in
the same folder waits ("Waiting for <thread> to finish…") and starts
when the first finishes. The process-wide ChdirToCwd is gone.
Storage keeps the 0.5.x layout: a folder's session is its first thread,
the index keeps one `sessions` entry per folder and adds `threads` and
`lastActiveThread`. Session files not in the index (after 0.5.x rewrote
it) are listed again from their headers. Nothing is written at startup.
The session dropdown lists the folder's threads (running ones marked),
then New thread and Open folder…. The control server gains listThreads,
newThread and selectThread; GRIT_MCP_PORT pins its port.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…latest thread A turn that fails while its thread isn't shown keeps its notice, and the prompt the failure rolled back out of history, on the Thread. Switching to the thread shows the notice and puts the prompt back into the input (unless the user is typing there); until then the dropdown marks the thread with "⚠ ". The no-API-key path now fails like the other errors, rolling back the unsent message. Opening a folder shows its most recently used thread instead of its first one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plain Thread struct in ChatFrame, (id, gen) callbacks, per-thread cwd for tools, one running turn per folder, no-migration storage with 0.5.x compatibility, background failures kept until viewed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ID_TREE_REFRESH and ID_EDITOR_SAVE were both wxID_HIGHEST + 21. The handler bound last runs first, so the tree menu's Refresh ran Save: it wrote the open file, or opened Save As when none was open. Give Refresh its own id. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…_seconds After a timeout or Escape the group got SIGTERM, but once bash itself died the loop returned before the SIGKILL step, so a grandchild that ignores SIGTERM lived on. SIGKILL the group after bash is reaped (only then: after a normal exit, `nohup … &` processes keep running). The model can pass timeout_seconds (default 30, clamped to 1..600) for slow builds and tests; the description says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Threads run tools at once, and two run_project set calls at the same time each loaded the file, added their entry and saved, so one entry was lost (16 of 320 kept with 16 threads saving at once). Get, Set and Forget now go through one mutex, and Save writes a temp file and renames it, so a reader (also in another gritcode process) never sees a half-written file. Load/Save become private. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nt threads Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…without a space The chat and summary streams split events on "\n\n" only, so a CRLF-delimited stream yielded no events at all, a last event without a closing blank line was dropped, and `data:` without a space was ignored. Each chunk also rescanned the whole buffer. One free function, TakeSseEvents, now does it per the SSE spec: lines end in "\n", "\r\n" or "\r", a blank line ends an event, its data lines are joined, one space after the colon is optional. Only the tail of the previous buffer is rescanned. When the stream ends OK, what is left counts as a last event; on errors the buffer still holds the raw body for the error message. The Exa web-search response uses it too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hildren Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Refresh fix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… (step 2) DeepSeek/Kilo: top-level threads get a task tool; each call runs a read-only child thread with a fresh context, concurrently with the rest of the batch, and its final message (or failure) becomes the call's result in call order. Claude Code: Agent/Task calls get a child thread that assembles the subagent's events with the top-level code. Children are view-only, listed under their parent and linked from its canvas; a thread and its subagents count as one owner of the folder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ads) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A new thread starts without the history of the folder's other threads. A short per-folder brief (what the project is, its layout and conventions, the current work) and a list of the folder's other titled threads now go into every thread's system prompt, next to AGENTS.md, and into Claude turns' appended prompt. The brief lives in the app data dir as briefs/<folder id>.md, keyed like sessions, so nothing is written into the user's repo. "Project brief…" in the thread dropdown opens a dialog to edit it; "Generate" streams a draft from DeepSeek Flash (or the free model without a key), with failures shown in the dialog. A new thread in a folder with other threads and no brief shows a one-line hint linking to the dialog; nothing is generated unasked. scripts/smoke/brief.py checks the injection; threads.py takes GRIT_MCP_PORT. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Subagents keep their note when the system prompt is rebuilt (brief or AGENTS.md change): SystemPrompt adds it for threads with a parent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The smoke tests ran their turns on the shared Kilo free tier, which stalls or drops one of two concurrent requests, so the concurrency checks failed at random and the `task` tool had no repeatable test. GRIT_FREE_MODEL_URL (a test/dev hook, read in RouteForIndex) overrides the free model's endpoint. scripts/smoke/fake_model.py is a stdlib, threaded, 127.0.0.1-only OpenAI-compatible SSE server scripted by the prompt: bash or arbitrary tool calls (task, write_file), a text reply after tool results, HTTP 500, and CRLF / unterminated-last-event framing on request, with a 1.1 s delay per reply. threads.py and subagents.py start it in-process by default (--live keeps the real Kilo behaviour). threads.py checks the step-3 SSE fixes end to end; subagents.py's task-tool section is now real checks: two calls in a batch run at once and report in call order, a failing child gives the parent an error result, children can't write_file, and cancelling the parent stops the child and kills its bash. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
grit_history_search leaves out the calling thread, takes scope "folder" and shows each hit's thread title (marking subagents). Titles and parents go into a new plain threads table in memory.db; the FTS5 turns table keeps the 0.5.x schema, so old versions and existing databases keep working without a rebuild. --reindex records titles and parents too, and --mcp-stdio routes its calls through DispatchTool (scope folder = its cwd). Smoke: scripts/smoke/history.py (old-format DB, reindex, scope, exclusion). threads.py and subagents.py now wait for their own port before the first control call, so they can't reach a neighbouring gritcode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Smoke tests passed a base port and the client then tried the next five ports too, which reached the user's own gritcode windows on 8765/8766. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An optional fixed-width pane left of the splitters lists the active folder's threads, most recent first with subagents nested: a state mark (running, waiting, failed until viewed), the title and a dim line with the current step (tool, writing, thinking, waiting for <thread>), the failure, or when it was last used. Clicking a row selects the thread, right-click stops a running one, "New thread" sits on top. The dropdown and the pane share one row list (FolderRows). The toggle is remembered in preferences and grows the window (or shares a tiled one) like the other panes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The calling thread stays searchable once compaction summarised part of it away. Smoke scripts use the exact-port control client. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A thread can work in its own git worktree (grit/<id>, under the data dir), so it writes alongside the folder's other threads: one running turn per work dir instead of per folder. Review shows the worktree's diff in the canvas, Merge commits its uncommitted changes and merges the branch with --no-ff (refused on a dirty checkout, aborted on conflicts), Discard asks before losing commits or changes. Worktree and branch are optional session fields. Smoke test: scripts/smoke/worktrees.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The session dropdown lists folders again (New Session…, then folders most recent first, ● when one has a running thread). The separate thread pane and its toolbar button are gone: the existing left pane gets a Session | Threads switch, remembered in preferences, and the Threads view holds New thread, New thread in worktree, Project brief… and the thread list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ut for now The left pane's Session | Threads switch becomes a bottom toolbar like the main pane's: a session icon and a threads icon (the current view in the text colour) and "+" for a new thread in the Threads view. The project brief is no longer edited by hand: the first new thread in a folder without one has it written in the background (DeepSeek Flash, the free model without a key), and later new threads reuse it. The new thread says it is being written and by which model, then shows the brief it starts with; a failure shows the model's error and the next new thread retries. Worktree threads are reverted (merge d48a624) until they are wanted again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DeepSeek users get DeepSeek Flash, free-model users the free model, and Claude users Sonnet through their Claude Code CLI (print mode, no tools, no saved session, material on stdin), so a folder's README and file names never go to a provider the user didn't pick. The brief test checks the Claude case with a stand-in CLI and that nothing reached the HTTP model. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drop the one-running-turn-per-folder lock and its waiting state: a turn starts as soon as it is sent, whatever else runs in the folder. Subagents stay read-only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A top-level thread in a git repo gets rules in its system prompt: don't move the shared checkout's branch or index, work in place by default, and take branch work, or bigger work while another thread is busy there, into a git worktree under the data dir. When a turn starts while other threads run in the same checkout, the user message gets a note naming them; the model sees it after the message and the canvas shows it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on change Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The input's text and attached images stay with the thread you switch away from and come back with it. Play keeps one run per folder, so Play in one project no longer stops another's, and its blocks stay with the thread Play was pressed in, put back in place when the canvas is rebuilt; they are still display-only. Also: a DeepSeek key from GRIT_DEEPSEEK_API_KEY for headless test instances, and the control API lists the model dropdown and can set the input. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A folder's mark is now ⚠ when a thread there failed unseen and ● when one is working or finished since it was last viewed; the thread on screen never counts, so the closed dropdown tells you about the folder's other threads. Subagents report through their parent, a turn you stopped leaves nothing to see. The Threads list marks the same threads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Several conversations per folder, running at the same time, plus subagents and a project brief. This is the 0.6.0 feature set.
Threads
Subagents
tasktool that runs a child thread in the background.Project brief
briefs/<id>.md), never in the repo.History search
grit_history_searchleaves out the calling thread, takesscope: "folder"and shows each hit's thread title.Fixes found along the way
data:without a space.Compatibility
The on-disk formats stay readable by 0.5.x: session files keep their format, the index adds a
threadskey 0.5.x ignores, andmemory.dbadds a table next to the unchanged FTS5turnstable. Downgrading shows each folder's first thread with full history.Testing
scripts/smoke/) against a local fake model server: threads, thread pane, subagents, brief, history, Play.🤖 Generated with Claude Code