Skip to content

feat(claude-tasks): split replies into a block hierarchy (splitReply)#314

Open
Stvad wants to merge 3 commits into
masterfrom
feat/claude-tasks-split-reply-hierarchy
Open

feat(claude-tasks): split replies into a block hierarchy (splitReply)#314
Stvad wants to merge 3 commits into
masterfrom
feat/claude-tasks-split-reply-hierarchy

Conversation

@Stvad

@Stvad Stvad commented Jul 4, 2026

Copy link
Copy Markdown
Owner

What

Cloud replies (the "browser emacs" mention flow) were always one big block. This adds splitReply — a per-backlinks-watcher flag, default ON — so a reply is split along its markdown outline into a block hierarchy under the mention: nested bullets → child blocks, headings nest their following content, fenced code stays whole.

Prompted by a reflection note asking for replies "split up among the blocks appropriately … a block hierarchy — maybe a question of prompting or injection." The answer turned out to be both: injection (deterministic parse → blocks) as the backbone, plus a light prompt nudge.

How (design)

  • Markdown, not structured output. The model keeps emitting notes-style markdown (its most reliable mode; degrades gracefully; streams readably). We don't force a JSON/tool-call block tree.
  • Reuse the app's own paste parser, not a second markdown dialect. Parsing + insertion happen app-side via a new create-blocks-from-markdown bridge command that runs parseMarkdownToBlocks and inserts the whole subtree in one repo.tx — atomic, so a failure never leaves a partial reply. Every block is tagged claude:reply.
  • Streamed placeholder reuse. With streamReply on, the live text still streams into a single placeholder; at the end that placeholder is reused as the reply's first root instead of being orphaned (new rootBlockId arg).
  • Prompt nudge ("the prompting half") appended when splitReply is on, so the run authors a nested outline that threads well.
  • splitReply: false keeps today's single-block, idempotent-retry terminal write.

Also: a latent paste-parser fix

Added fenced-code-block handling to parseMarkdownToBlocks: a ``` block now stays one block and its inner -/# lines aren't misparsed as bullets/headers. This fixes code-mangling for both paste and replies.

Files

  • packages/agent-cli/src/protocol.ts — new create-blocks-from-markdown command (schema, unions, registry).
  • src/plugins/agent-runtime/{protocol,commands}.ts — app-side handler (atomic tx, append-after-existing-children, placeholder reuse) + context wiring.
  • src/utils/markdownParser.ts — fenced-code handling.
  • packages/claude-tasks/src/{config,prompt,engine,graph}.tssplitReply flag (default true), outline nudge, graph.createReplyTree, success-path wiring.
  • Tests: app-side handler (dataCommands), paste parser (fences), daemon engine/prompt.

Verification

yarn run check green — compile + lint + 4605 tests + sync-config/rpc/service-role checks.

Notes for the reviewer

  • splitReply defaults true, so all backlinks replies now thread. Existing single-line replies are unaffected (they land as one block either way). Set false per-watcher to keep the idempotent single-block write.
  • Requires an app build new enough to handle the new bridge command; against an older tab the run errors visibly rather than silently falling back (deploy app + daemon together).

🤖 Generated with Claude Code

https://claude.ai/code/session_01MngxzayB9nBcwMhoNZPb6v

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 800077aeb8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/utils/markdownParser.ts Outdated
const fenceLine = lines[idx];
fenceLines.push(stripOpeningIndent(fenceLine));
idx++;
if (fenceLine.trim() === '```') break; // include the closing fence, then stop

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Accept matching longer code fences

When a reply uses a longer Markdown fence such as to show content that itself contains triple backticks, this check never recognizes the matching closing fence, so the parser consumes the rest of the reply as one code block and the intended sibling/child blocks are lost. Track the opening fence marker/length and close on a fence of at least that length instead of only ```.

Useful? React with 👍 / 👎.

@Stvad Stvad force-pushed the feat/claude-tasks-split-reply-hierarchy branch from 800077a to db08d62 Compare July 4, 2026 18:42
@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://Stvad.github.io/knowledge-medium/pr-preview/pr-314/

Built to branch gh-pages at 2026-07-07 02:48 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: db08d62d0f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/plugins/agent-runtime/commands.ts Outdated
Comment on lines +379 to +380
const existing = await tx.get(rootBlockId)
if (!existing) throw new Error(`create-blocks-from-markdown: rootBlockId ${rootBlockId} not found`)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Treat stale stream roots as optional

When streamReply and splitReply are both enabled, rootBlockId is only the best-effort placeholder created at run start. If the user deletes it before the successful run finishes, this throw makes the daemon treat the completed answer as an infrastructure error instead of posting the final reply; if the user moves the placeholder, the later update overwrites a block that is no longer under parentId. Validate that the reusable root still exists as a live child of parentId, and otherwise fall back to creating the split roots fresh.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9602934d25

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/utils/markdownParser.ts Outdated
let currentLineType: string;
let processedContent: string;

const fenceOpen = /^(`{3,})/.exec(trimmedLine);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve tilde-fenced code blocks

When a reply or paste uses a Markdown tilde fence such as ~~~ts, this opener is not recognized because the fence parser only matches backticks, so any - or # lines inside the fenced code are still split into outline blocks. Since split replies now rely on this parser and promise that fenced code stays whole, handle ~{3,} fences with the same matching-character/length rules as backtick fences.

Useful? React with 👍 / 👎.

@Stvad Stvad force-pushed the feat/claude-tasks-split-reply-hierarchy branch from d7c953a to 796ae94 Compare July 5, 2026 19:51

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 796ae9443a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// its current last child (which already includes a reused placeholder).
const existingChildren = await tx.childrenOf(input.parentId, workspaceId)
const lastKeyByParent = new Map<string, string | null>([
[input.parentId, existingChildren.at(-1)?.orderKey ?? null],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Seed root insertion from the reused placeholder

When streamReply + splitReply reuses a placeholder that is no longer the last child—for example, the user adds a sibling after the live “Claude is working…” block while the run is streaming—this cursor is seeded from the last existing child. The first parsed root keeps the placeholder’s old order key, but every later root is created after the newer sibling, so one reply is split around unrelated user content instead of landing as a contiguous tree.

Useful? React with 👍 / 👎.

@Stvad Stvad force-pushed the feat/claude-tasks-split-reply-hierarchy branch from 796ae94 to 97d18c7 Compare July 6, 2026 04:50

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 97d18c7e47

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

content: block.content,
...(mergedProperties !== undefined ? {properties: mergedProperties} : {}),
})
idMap.set(block.id, reusableRoot.id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Seed child cursor when reusing the placeholder

When streamReply reuses a placeholder that the user has already added sub-blocks to, this maps the parsed first root onto an existing block but leaves lastKeyByParent without an entry for that existing block. The first parsed child of the reply then reaches the keyAtEnd(lastKeyByParent.get(realParentId) ?? null) path as if the placeholder had no children, so it can be ordered around the user's existing children instead of preserving them and appending the generated subtree. Seed lastKeyByParent from tx.childrenOf(reusableRoot.id, workspaceId) before continuing.

Useful? React with 👍 / 👎.

Stvad and others added 3 commits July 6, 2026 19:45
Cloud replies were always one big block. Add `splitReply` (backlinks
watchers, default ON) so a reply is split along its markdown outline into
a block hierarchy under the mention — nested bullets → child blocks,
headings nest their content, fenced code stays whole.

Reuse the app's own paste parser instead of a second markdown dialect:
parsing + insertion happen APP-SIDE via a new `create-blocks-from-markdown`
bridge command that runs `parseMarkdownToBlocks` and inserts the whole
subtree in one `repo.tx` (atomic — never a partial reply), tagging every
block `claude:reply`. A streamed placeholder is reused as the first root
rather than orphaned.

Also improve the shared paste parser: fenced code blocks now stay one
block (markers/headers inside are not misparsed) — a latent paste bug
fixed for both paste and replies.

The spawned run is nudged to author a nested outline (the "prompting"
half; the parsing is the "injection" half). Set `splitReply: false` to
keep the single-block, idempotent-retry terminal write.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MngxzayB9nBcwMhoNZPb6v
- markdown parser: close a fenced block on a run of AT LEAST as many
  backticks as the opener (CommonMark), so a ````-fenced reply that wraps
  content containing ``` no longer swallows the rest of the reply.
- create-blocks-from-markdown: reuse the streamed placeholder only when
  it's still a LIVE CHILD of the mention. If the user deleted or moved it
  mid-run, create the split roots fresh instead of throwing away the
  billed answer (deleted) or overwriting a moved block.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MngxzayB9nBcwMhoNZPb6v
The fence parser only matched backtick fences, so a ~~~-fenced block
(the canonical way to fence code that itself contains ```) had its inner
- / # lines mis-split into outline blocks. Generalize to both ` ` ` and
~ with the same matching-char / minimum-length close rule.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MngxzayB9nBcwMhoNZPb6v
@Stvad Stvad force-pushed the feat/claude-tasks-split-reply-hierarchy branch from 97d18c7 to 8b1f43f Compare July 7, 2026 02:47
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

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