feat: the social graph atlas — exploration 0419 - #674
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
…k directly Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
|
Warning Review limit reached
Next review available in: 7 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (11)
📝 WalkthroughWalkthroughThe PR adds transcript-aware social imports, YouTube transcript processing, TikTok enrichment, social retrieval policies, new feed views, bounded canvas projections, saved-lens handoff, and full-text indexing for imported social content. ChangesSocial Graph Atlas
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Preview removed for PR #674. |
There was a problem hiding this comment.
Actionable comments posted: 18
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
packages/social/src/import/stage-archive.ts (1)
186-193: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
importRunIddoes not includefetchTranscripts.
includeSensitiveandselectedBucketsare part of theimportRunIdhash, butfetchTranscriptsis not. Two stagings of the same archive with the same buckets, sensitivity, andimportedAtproduce the same import-run id even whenfetchTranscriptsdiffers.This matters because
apps/web/src/routes/social-import.tsxreusesrecord.importedAtwhen resuming a paused import (see the linked comment there). Committing that resumed stage overwrites the original import-run node'soptionsJson, since both stagings resolve to the same deterministic id.Include
fetchTranscriptsin theimportRunIdinputs, or otherwise ensure the transcript preference is preserved across resume rather than silently collapsed by an id collision.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/social/src/import/stage-archive.ts` around lines 186 - 193, Update the importRunId construction in the staging flow to include the fetchTranscripts preference alongside selectedBuckets and includeSensitive, ensuring stages resumed with the same importedAt but different transcript settings receive distinct deterministic IDs and do not overwrite each other’s optionsJson.apps/web/src/routes/social-import.tsx (1)
296-303: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winPersist and pass
fetchTranscriptsthrough resume imports.
handleResumeImportstages the archive withfetchTranscriptsomitted, sostageBrowserSocialArchivebuilds the selection with transcripts disabled. The resume record stores the originalimportedAtbut notfetchTranscripts, so the resumed import-run draft can have the same deterministic id while itsoptionsJsonflips the user’s explicit transcript preference tofalse. StorefetchTranscriptson the resume record and pass it through when resuming.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/src/routes/social-import.tsx` around lines 296 - 303, Update the resume record creation and handling in handleResumeImport to persist the user’s explicit fetchTranscripts setting alongside importedAt. When calling stageBrowserSocialArchive, pass record.fetchTranscripts so resumed imports preserve the original transcript-selection preference and deterministic draft options.apps/web/src/workers/social-import.worker.ts (1)
257-267: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winPass the stored
fetchTranscriptsflag when rebuilding the draft stream.
handleStagestoresfetchTranscriptsonWorkerStagedResult(Line 135), butgetStageDraftStreamnever reads it. Chunk reads therefore re-stream drafts with transcript fetching disabled, while the staging pass ran with it enabled. The counts reported at stage time and the drafts committed from chunks then disagree.The main-thread path in
apps/web/src/lib/social-import-worker-client.ts(Line 504) already forwards the stored flag, so the worker and main-thread execution modes currently produce different results for the same archive.🐛 Proposed fix
generator: streamSocialImportNodeDrafts({ manifest: stagedResult.manifest, adapters, readJsonEntry, readTextEntry, buckets: stagedResult.buckets, includeSensitive: stagedResult.includeSensitive, + fetchTranscripts: stagedResult.fetchTranscripts, importedAt: stagedResult.importedAt, includeSourceRecords }),🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/src/workers/social-import.worker.ts` around lines 257 - 267, Update getStageDraftStream’s streamSocialImportNodeDrafts call to read the stored fetchTranscripts value from stagedResult and pass it through when rebuilding the draft stream. Keep the existing staging and main-thread behavior aligned so chunk processing preserves the transcript-fetching setting used by handleStage.
🧹 Nitpick comments (5)
packages/social/src/transcripts/youtube.ts (1)
183-191: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winNo per-request timeout on the caption fetch.
fetchImpl(url, signal ? { signal } : {})relies entirely on the caller-suppliedsignal.runTranscriptFetchPassawaits each target sequentially, so a single stalled request (no response, no error) can block the entire scheduled pass indefinitely, delaying every other target in the run.Add a per-request timeout (for example via
AbortSignal.timeout()combined with the caller'ssignal) so one hung request cannot stall the whole pass.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/social/src/transcripts/youtube.ts` around lines 183 - 191, Add a per-request timeout to the caption fetch in runTranscriptFetchPass by combining the caller-provided signal with a timeout signal before invoking fetchImpl. Preserve caller cancellation and existing error handling, while ensuring a stalled request aborts and returns the current error result instead of blocking the scheduled pass indefinitely.packages/social/src/transcripts/schedule.ts (1)
83-85: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winMake the pacing delay respond to
signal.
delayFnignoresoptions.signal. After an abort, the pass still waits the full interval plus jitter before the check at Line 77 runs. With the defaults that is up to 2.5 s of unresponsive cancellation per abort.Pass the signal into the delay so a cancelled pass returns promptly.
♻️ Proposed change
-function defaultDelay(ms: number): Promise<void> { - return new Promise((resolve) => setTimeout(resolve, ms)) +function defaultDelay(ms: number, signal?: AbortSignal): Promise<void> { + return new Promise((resolve) => { + const timer = setTimeout(() => { + signal?.removeEventListener('abort', onAbort) + resolve() + }, ms) + function onAbort(): void { + clearTimeout(timer) + resolve() + } + signal?.addEventListener('abort', onAbort, { once: true }) + }) }if (attempted > 0) { - await delayFn(intervalMs + Math.floor(random() * jitterMs)) + await delayFn(intervalMs + Math.floor(random() * jitterMs), options.signal) + if (options.signal?.aborted) { + stoppedEarly = true + break + } }The
delayFnoption type needs the extra parameter:delayFn?: (ms: number, signal?: AbortSignal) => Promise<void>. Existing test stubs that accept onlymsstay compatible.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/social/src/transcripts/schedule.ts` around lines 83 - 85, Update the retry pacing delay in the schedule flow to pass the current AbortSignal to delayFn, allowing cancellation to interrupt the wait and return promptly. Extend the delayFn option type to accept an optional AbortSignal while preserving compatibility with existing one-argument stubs.packages/social/src/transcripts/states.ts (1)
96-97: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winDo not silently repair a
totalsmaller than the state list.Line 96 raises an undersized
input.totaltoinput.states.length. That case means the caller supplied more states than targets, which is a contract violation, and the summary then reports a plausible total that no caller asked for. Fail loudly instead so the miscount surfaces at its source.♻️ Proposed change
- const total = Math.max(input.total ?? input.states.length, input.states.length) + const total = input.total ?? input.states.length + if (total < input.states.length) { + throw new Error( + `transcript run total ${total} is smaller than the ${input.states.length} recorded states` + ) + } counts['not-attempted'] += total - input.states.lengthAs per coding guidelines: "do not use catches, defaults, or coercions that turn failure into a plausible successful value".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/social/src/transcripts/states.ts` around lines 96 - 97, Remove the Math.max-based coercion in the total calculation and preserve the caller-provided input.total when present. In the transcript state summary flow, validate that total is not smaller than input.states.length and fail loudly on violation; continue deriving the total from input.states.length only when total is absent.Source: Coding guidelines
packages/social/src/transcripts/nodes.ts (1)
128-138: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueOptional: remove the duplicated length expression.
additionat Line 130 measures the cue against the current segment. Line 137 recomputes the same expression becauseflush()may have resetcurrentLength. The duplication is correct but reads as an accident.♻️ Proposed refactor
for (const cue of usable) { const text = cue.text.trim() - const addition = currentLength === 0 ? text.length : text.length + 1 + const withSeparator = (length: number): number => (length === 0 ? text.length : text.length + 1) - if (currentLength > 0 && currentLength + addition > maxChars) { + if (currentLength > 0 && currentLength + withSeparator(currentLength) > maxChars) { flush() } current.push(cue) - currentLength += currentLength === 0 ? text.length : text.length + 1 + currentLength += withSeparator(currentLength) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/social/src/transcripts/nodes.ts` around lines 128 - 138, Refactor the cue-length calculation in the loop that builds segments so the value used for the capacity check is also reused when updating currentLength after flush(). Preserve the existing behavior, including the separator length for non-empty segments and recalculating the effective length after flush resets the segment state.packages/react/src/components/SavedViewRunner.tsx (1)
2238-2243: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winHoist the
placednode-id set out of the filter callback.
new Set(input.nodes.map(...))runs once per edge inside.filter(). For n nodes and m edges this is O(n·m) instead of O(n+m). Node count is bounded byVISUAL_CANVAS_PROJECTION_LIMIT, but edge count (request.edges) is not bounded before this filter runs, so this can add up on saved views with many relationships.⚡ Proposed fix
- // Only relationships between nodes that made the projection cut; an edge - // to something that was not placed would render as a line to nowhere. - edges: (input.edges ?? []).filter((edge) => { - const placed = new Set(input.nodes.map((node) => node.id)) - return placed.has(edge.sourceId) && placed.has(edge.targetId) - }), + // Only relationships between nodes that made the projection cut; an edge + // to something that was not placed would render as a line to nowhere. + edges: (() => { + const placedNodeIds = new Set(input.nodes.map((node) => node.id)) + return (input.edges ?? []).filter( + (edge) => placedNodeIds.has(edge.sourceId) && placedNodeIds.has(edge.targetId) + ) + })(),🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/react/src/components/SavedViewRunner.tsx` around lines 2238 - 2243, Hoist the node-id Set construction out of the edges filter callback in the surrounding projection logic. Build the `placed` set once from `input.nodes`, then reuse it for both endpoint checks so filtering remains O(n+m).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.changeset/social-graph-atlas-0419.md:
- Around line 1-4: Update the changeset entry for `@xnetjs/sqlite` from minor to
patch, while leaving the `@xnetjs/react` release level unchanged.
- Around line 1-4: Add the publishable package `@xnetjs/views` to the package
list in the changeset front matter alongside `@xnetjs/sqlite` and
`@xnetjs/react`, preserving the existing minor release designation.
In `@docs/explorations/0419_`[-]_SOCIAL_GRAPH_ATLAS.md:
- Line 52: Update the human-readable “Live embeds” table entry to capitalize the
platform names as YouTube/Instagram/TikTok, while preserving lowercase values
only where they represent machine-readable provider keys.
- Line 469: Fix the blockquote spacing at the referenced location by either
prefixing the blank line with “>” to keep it within the blockquote or removing
the blank line, ensuring markdownlint MD028 passes.
- Around line 341-357: Update the enrichment flow around the “else no captions /
blocked” branch so “no captions” and “fetch blocked” are recorded as distinct
terminal states, using separate status codes or a distinguishing reason field
rather than a shared exhausted value. Preserve “not yet attempted” as a separate
state on the enrichment node so per-state counts remain accurate.
- Around line 44-57: Update the repository inventory in the Executive Summary
and the related “Current State In The Repository” section to clearly label it as
historical, specifically “before this PR,” or revise its statuses and
descriptions to match the implemented checklist items. Ensure references to
canvas projection, TikTok feeds, transcripts, and social retrieval no longer
present completed work as missing or unwired.
In `@packages/social/src/enrichment/fetch.ts`:
- Around line 150-230: Update the hub-proxy branch in fetchEnrichmentForTarget
to return a typed SocialUnfurlMetadataPayload instead of throwing for fetch
failures and invalid JSON. Catch network and parsing errors, classify 403/429
responses as blocked, and return an error status with a reason for other non-ok
responses or malformed payloads, preserving the existing resolved-success and
thumbnail-capture flow.
In `@packages/social/src/import/run-options.ts`:
- Around line 30-43: Update parseSocialImportRunOptions so missing options
continue returning DEFAULT_SOCIAL_IMPORT_RUN_OPTIONS, while JSON parse failures
are distinguishable and surfaced to callers through a typed malformed-options
result or error. Preserve the conservative fetchTranscripts: false value, but do
not silently map corrupt input to the absent-options default.
In `@packages/social/src/retrieval/context-packs.ts`:
- Around line 92-105: The createSensitiveSocialContextPack function must use a
distinct context-pack id instead of social.pack.saved-library. Update its id to
the established sensitive-pack SocialContextPackId, leaving the query, seeds,
limit, and includeMessages scope unchanged.
In `@packages/social/src/retrieval/retrieval.test.ts`:
- Around line 67-85: Extend the existing “widens only when asked” test around
createSocialRetrievalScope to cover allowPrivacyClasses. Create a scope with
allowPrivacyClasses: ['billing'], assert a candidate with privacyClass 'billing'
is retrievable, and assert a candidate with a different excluded privacy class
remains unretrievable.
In `@packages/social/src/transcripts/nodes.ts`:
- Around line 128-142: Update the transcript segmentation logic around the loop
over usable cues and final flush so no emitted segment text exceeds the
20,000-character SocialContent.searchText limit. Split any oversized cue text
into whitespace-boundary chunks before adding them to current, preserving cue
order and existing separator accounting; ensure createTranscriptContentDrafts()
receives only segments whose text is within the schema cap.
In `@packages/social/src/transcripts/youtube.ts`:
- Around line 183-213: Update the response-body handling in the transcript fetch
flow around parseYouTubeTranscript so response.text() failures become a distinct
error outcome rather than an empty string. Preserve the existing retry/blocked
handling semantics, but return or propagate a typed error result for unreadable
bodies; only treat successfully read, genuinely empty or unparsable caption
content according to the intended parser outcome, preventing failures from
reaching the terminal no-captions result.
- Around line 156-215: Update the response-body handling in
createYouTubeTranscriptFetcher so successful timedtext responses are inspected
for known refusal or BotGuard/PoToken indicators before an empty parse result is
treated as a missing caption track. Map recognized refusal bodies to the
existing blocked/error outcome, while preserving the current retry behavior for
genuinely empty caption misses and the normal cue return path.
In `@packages/views/src/canvas-view/query-frames.tsx`:
- Around line 437-447: Update applySocialCanvasProjection to compute an origin
that places the plan away from existing canvas objects, then pass that origin to
applySocialCanvasProjectionPlan instead of relying on the default (0, 0) origin.
Preserve the existing empty-plan, undo-boundary, and result behavior.
In `@packages/views/src/canvas-view/social-projection.ts`:
- Around line 113-120: Update describeSocialCanvasProjection to use singular
“card” and “connection” when nodeCount or edgeCount equals one, while retaining
plural forms otherwise; also update the expected string in
packages/views/src/canvas-view/social-projection.test.ts lines 127-131 to match
the corrected wording.
In `@packages/views/src/data-workspace/pending-canvas-lens.ts`:
- Around line 62-80: The readPending function must validate the stored
projection before returning a PendingCanvasLens. Add or reuse a minimal
structural validator for SocialCanvasProjectionPlan, and return null when
projection is malformed while preserving the existing canvasId/viewId checks and
valid payload behavior.
In `@site/public/llms-full.txt`:
- Around line 10626-10630: Update the ADR passage in the “The layer
commoditised” section to remove Zed ACP from the meta-harness examples or
separate it into an appropriate protocol-layer list, ensuring every project
grouped together belongs to the same composition layer before publication.
In
`@site/src/data/changelog/2026-08-01-your-imported-social-library-is-now-legi.json`:
- Around line 4-5: Update the changelog entry around the title and summary to
document that existing databases must run the nodes_fts rebuild migration via
rebuildFTS() before transcript search includes previously stored imported rows;
alternatively, wire rebuildFTS() into the applicable migration path so the
upgrade performs it automatically.
---
Outside diff comments:
In `@apps/web/src/routes/social-import.tsx`:
- Around line 296-303: Update the resume record creation and handling in
handleResumeImport to persist the user’s explicit fetchTranscripts setting
alongside importedAt. When calling stageBrowserSocialArchive, pass
record.fetchTranscripts so resumed imports preserve the original
transcript-selection preference and deterministic draft options.
In `@apps/web/src/workers/social-import.worker.ts`:
- Around line 257-267: Update getStageDraftStream’s streamSocialImportNodeDrafts
call to read the stored fetchTranscripts value from stagedResult and pass it
through when rebuilding the draft stream. Keep the existing staging and
main-thread behavior aligned so chunk processing preserves the
transcript-fetching setting used by handleStage.
In `@packages/social/src/import/stage-archive.ts`:
- Around line 186-193: Update the importRunId construction in the staging flow
to include the fetchTranscripts preference alongside selectedBuckets and
includeSensitive, ensuring stages resumed with the same importedAt but different
transcript settings receive distinct deterministic IDs and do not overwrite each
other’s optionsJson.
---
Nitpick comments:
In `@packages/react/src/components/SavedViewRunner.tsx`:
- Around line 2238-2243: Hoist the node-id Set construction out of the edges
filter callback in the surrounding projection logic. Build the `placed` set once
from `input.nodes`, then reuse it for both endpoint checks so filtering remains
O(n+m).
In `@packages/social/src/transcripts/nodes.ts`:
- Around line 128-138: Refactor the cue-length calculation in the loop that
builds segments so the value used for the capacity check is also reused when
updating currentLength after flush(). Preserve the existing behavior, including
the separator length for non-empty segments and recalculating the effective
length after flush resets the segment state.
In `@packages/social/src/transcripts/schedule.ts`:
- Around line 83-85: Update the retry pacing delay in the schedule flow to pass
the current AbortSignal to delayFn, allowing cancellation to interrupt the wait
and return promptly. Extend the delayFn option type to accept an optional
AbortSignal while preserving compatibility with existing one-argument stubs.
In `@packages/social/src/transcripts/states.ts`:
- Around line 96-97: Remove the Math.max-based coercion in the total calculation
and preserve the caller-provided input.total when present. In the transcript
state summary flow, validate that total is not smaller than input.states.length
and fail loudly on violation; continue deriving the total from
input.states.length only when total is absent.
In `@packages/social/src/transcripts/youtube.ts`:
- Around line 183-191: Add a per-request timeout to the caption fetch in
runTranscriptFetchPass by combining the caller-provided signal with a timeout
signal before invoking fetchImpl. Preserve caller cancellation and existing
error handling, while ensuring a stalled request aborts and returns the current
error result instead of blocking the scheduled pass indefinitely.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 691884e1-2170-471d-834f-00c7413f41ad
📒 Files selected for processing (57)
.changeset/social-graph-atlas-0419.mdapps/electron/src/renderer/components/CanvasView.tsxapps/electron/src/renderer/components/DataWorkspaceView.tsxapps/electron/src/renderer/shell/use-document-shell.tsapps/web/src/components/CanvasView.tsxapps/web/src/components/DataWorkspaceView.tsxapps/web/src/components/SavedViewTab.tsxapps/web/src/lib/social-import-worker-client.tsapps/web/src/lib/social-import-worker-protocol.tsapps/web/src/routes/social-import.tsxapps/web/src/workers/social-import.worker.tsdocs/explorations/0419_[-]_SOCIAL_GRAPH_ATLAS.mdpackages/react/etc/react.api.mdpackages/react/src/components/SavedViewRunner.tsxpackages/react/src/index.tspackages/social/src/__tests__/views-lenses-projection.test.tspackages/social/src/enrichment/enrichment.test.tspackages/social/src/enrichment/fetch.tspackages/social/src/enrichment/index.tspackages/social/src/enrichment/queue.tspackages/social/src/enrichment/run-options.test.tspackages/social/src/enrichment/targets.tspackages/social/src/feeds/defaults.tspackages/social/src/feeds/tiktok-and-timeline.test.tspackages/social/src/import/core.tspackages/social/src/import/run-options.tspackages/social/src/import/stage-archive.tspackages/social/src/import/types.tspackages/social/src/index.tspackages/social/src/retrieval/context-packs.tspackages/social/src/retrieval/index.tspackages/social/src/retrieval/retrieval.test.tspackages/social/src/retrieval/scope.tspackages/social/src/schemas/import.tspackages/social/src/transcripts/index.tspackages/social/src/transcripts/nodes.tspackages/social/src/transcripts/schedule.tspackages/social/src/transcripts/states.tspackages/social/src/transcripts/transcripts.test.tspackages/social/src/transcripts/types.tspackages/social/src/transcripts/youtube.tspackages/sqlite/src/fts.test.tspackages/sqlite/src/fts.tspackages/views/src/canvas-view/index.tspackages/views/src/canvas-view/query-frames.tsxpackages/views/src/canvas-view/social-projection.test.tspackages/views/src/canvas-view/social-projection.tspackages/views/src/data-workspace/DataWorkspaceCore.tsxpackages/views/src/data-workspace/index.tspackages/views/src/data-workspace/pending-canvas-lens.test.tspackages/views/src/data-workspace/pending-canvas-lens.tspackages/views/src/index.tspackages/views/src/social-enrichment/index.tspackages/views/src/social-enrichment/useSocialFeedEnrichment.tssite/public/llms-full.txtsite/src/data/changelog/2026-08-01-your-imported-social-library-is-now-legi.jsonvitest.config.ts
| --- | ||
| '@xnetjs/sqlite': minor | ||
| '@xnetjs/react': minor | ||
| --- |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Use a patch bump for @xnetjs/sqlite.
The PR describes the SQLite change as an FTS fix. It corrects existing indexing behavior and does not add a public SQLite API. Change the release level from minor to patch.
Proposed change
-'`@xnetjs/sqlite`': minor
+'`@xnetjs/sqlite`': patchAs per coding guidelines, fix: produces a patch release; the PR objective describes this change as an FTS fix.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| --- | |
| '@xnetjs/sqlite': minor | |
| '@xnetjs/react': minor | |
| --- | |
| --- | |
| '`@xnetjs/sqlite`': patch | |
| '`@xnetjs/react`': minor | |
| --- |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.changeset/social-graph-atlas-0419.md around lines 1 - 4, Update the
changeset entry for `@xnetjs/sqlite` from minor to patch, while leaving the
`@xnetjs/react` release level unchanged.
Source: Coding guidelines
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
manifest="$(fd -a -t f 'package.json' packages/views | head -n1)"
test -n "$manifest"
python - "$manifest" <<'PY'
import json
import sys
with open(sys.argv[1], encoding="utf-8") as file:
package = json.load(file)
print(package["name"])
PY
rg -n 'SavedViewCanvasProjectionEdge|SavedViewVisualCanvasProjectionRequest' \
packages/views/src packages/react/src
rg -n '`@xnetjs/views`|packages/views' .changesetRepository: crs48/xNet
Length of output: 2347
Add @xnetjs/views to this changeset.
packages/views is publishable under @xnetjs/views, and this changeset currently lists only @xnetjs/sqlite and @xnetjs/react. Add @xnetjs/views so the publish tool includes the package for the projection API changes.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.changeset/social-graph-atlas-0419.md around lines 1 - 4, Add the
publishable package `@xnetjs/views` to the package list in the changeset front
matter alongside `@xnetjs/sqlite` and `@xnetjs/react`, preserving the existing
minor release designation.
Source: Coding guidelines
| ## Executive Summary | ||
|
|
||
| | Pillar of the vision | Status | What exists / what's missing | | ||
| | --------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------- | | ||
| | Import YouTube/IG/TikTok archives | ✅ Shipped | `packages/social` adapters, staging pipeline, resumable jobs, deterministic IDs | | ||
| | Canonical graph schema | ✅ Shipped | 13 `social/*` schemas: Actor, Content, Interaction, Collection, CollectionItem… | | ||
| | Flip-through renderings | ✅ Shipped | `SavedViewRunner` presentation modes: `table \| cards \| timeline \| canvas \| graph \| feed` | | ||
| | Thumbnails + metadata enrichment | 🚧 Partial | YouTube + Instagram via hub `/unfurl`; **web-only**, no TikTok, no Electron | | ||
| | Live embeds | ✅ Shipped | `EMBED_PROVIDERS` + iframe policy + canvas card renderers for youtube/instagram/tiktok | | ||
| | Canvas projection of social graph | 🚧 Built, unwired | `createSocialCanvasProjectionPlan()` exists + tested, **called from no app surface** | | ||
| | Calendar of watch/like history | 🚧 Partial | Interactions carry timestamps; calendar view exists; no seeded social calendar view | | ||
| | TikTok feed views | ❌ Missing | Feed seeds cover only YouTube ×2 and Instagram ×2 | | ||
| | Video transcripts | ❌ Missing | Nothing fetches or stores them; Takeout doesn't ship them; oEmbed gives title only | | ||
| | Agent access to social context | 🚧 Partial | `xnet_search`/FTS work over `searchText`, but no transcript corpus and no social-aware retrieval profile | |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Mark the repository inventory as historical.
The TL;DR and “Current State In The Repository” sections describe canvas projection, TikTok feeds, transcripts, and social retrieval as missing or unwired. The implementation checklist later marks these items [x]. Label the inventory “before this PR” or update it to the post-change state.
Also applies to: 149-181
🧰 Tools
🪛 LanguageTool
[uncategorized] ~52-~52: The official name of this popular video platform is spelled with a capital “T”.
Context: ...rame policy + canvas card renderers for youtube/instagram/tiktok ...
(YOUTUBE)
[uncategorized] ~52-~52: Did you mean “TikTok” (= social networking app)?
Context: ...as card renderers for youtube/instagram/tiktok | | Canvas ...
(TIK_TOK)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/explorations/0419_`[-]_SOCIAL_GRAPH_ATLAS.md around lines 44 - 57,
Update the repository inventory in the Executive Summary and the related
“Current State In The Repository” section to clearly label it as historical,
specifically “before this PR,” or revise its statuses and descriptions to match
the implemented checklist items. Ensure references to canvas projection, TikTok
feeds, transcripts, and social retrieval no longer present completed work as
missing or unwired.
| | Canonical graph schema | ✅ Shipped | 13 `social/*` schemas: Actor, Content, Interaction, Collection, CollectionItem… | | ||
| | Flip-through renderings | ✅ Shipped | `SavedViewRunner` presentation modes: `table \| cards \| timeline \| canvas \| graph \| feed` | | ||
| | Thumbnails + metadata enrichment | 🚧 Partial | YouTube + Instagram via hub `/unfurl`; **web-only**, no TikTok, no Electron | | ||
| | Live embeds | ✅ Shipped | `EMBED_PROVIDERS` + iframe policy + canvas card renderers for youtube/instagram/tiktok | |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Capitalize platform names in the prose.
Use YouTube/Instagram/TikTok instead of youtube/instagram/tiktok in this human-readable table. Keep lowercase only for machine-readable provider keys.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~52-~52: The official name of this popular video platform is spelled with a capital “T”.
Context: ...rame policy + canvas card renderers for youtube/instagram/tiktok ...
(YOUTUBE)
[uncategorized] ~52-~52: Did you mean “TikTok” (= social networking app)?
Context: ...as card renderers for youtube/instagram/tiktok | | Canvas ...
(TIK_TOK)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/explorations/0419_`[-]_SOCIAL_GRAPH_ATLAS.md at line 52, Update the
human-readable “Live embeds” table entry to capitalize the platform names as
YouTube/Instagram/TikTok, while preserving lowercase values only where they
represent machine-readable provider keys.
Source: Linters/SAST tools
| Q->>Q: pick captioned video, jittered delay | ||
| Q->>YT: fetch caption track (user's residential IP) | ||
| alt captions exist | ||
| YT-->>Q: timed text (VTT/JSON) | ||
| Q->>S: upsert SocialContent{kind: transcript,\nrelation → video, deterministic id} | ||
| S->>F: index transcript text | ||
| else no captions / blocked | ||
| YT-->>Q: 404 / block | ||
| Q->>S: mark enrichment status=exhausted\n(loud, distinguishable from "absent") | ||
| end | ||
| AI->>F: "what did I watch about fermentation?" | ||
| F-->>AI: transcript hits → linked videos → collections | ||
| ``` | ||
|
|
||
| Per the repo's error rule: "no captions available," "fetch blocked," and | ||
| "not yet attempted" must be three distinguishable states on the enrichment | ||
| node — a truncated trickle run is not a completed one. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Keep transcript terminal states distinct in the design record.
The else no captions / blocked branch records one status=exhausted, but the following rule requires no captions, fetch blocked, and not yet attempted to remain distinguishable. Show separate status codes or a reason field for the two failure paths. Otherwise, the implementation can report incorrect per-state counts.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/explorations/0419_`[-]_SOCIAL_GRAPH_ATLAS.md around lines 341 - 357,
Update the enrichment flow around the “else no captions / blocked” branch so “no
captions” and “fetch blocked” are recorded as distinct terminal states, using
separate status codes or a distinguishing reason field rather than a shared
exhausted value. Preserve “not yet attempted” as a separate state on the
enrichment node so per-state counts remain accurate.
| > `runTranscriptFetchPass` with the **transport stubbed**: the accounting | ||
| > invariant (every target lands in exactly one terminal state, and the states | ||
| > sum to 50) is genuinely verified; a live network run against YouTube is not. | ||
|
|
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Fix the blockquote spacing.
The blank line at Line 469 triggers markdownlint MD028. Prefix the line with > or remove the blank line.
🧰 Tools
🪛 markdownlint-cli2 (0.23.1)
[warning] 469-469: Blank line inside blockquote
(MD028, no-blanks-blockquote)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/explorations/0419_`[-]_SOCIAL_GRAPH_ATLAS.md at line 469, Fix the
blockquote spacing at the referenced location by either prefixing the blank line
with “>” to keep it within the blockquote or removing the blank line, ensuring
markdownlint MD028 passes.
Source: Linters/SAST tools
| const applySocialCanvasProjection = useCallback( | ||
| (plan: SocialCanvasProjectionPlan): ApplySocialCanvasProjectionResult | null => { | ||
| if (!doc || plan.nodes.length === 0) return null | ||
|
|
||
| const result = applySocialCanvasProjectionPlan(doc, plan) | ||
| onUndoBoundary?.() | ||
| return result | ||
| }, | ||
| [doc, onUndoBoundary] | ||
| ) | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check how createSocialCanvasProjectionPlan computes bounds, and whether
# callers of applySocialCanvasProjection ever pass a non-default origin.
rg -n "createSocialCanvasProjectionPlan" packages/social/src -A 15
rg -nP "applySocialCanvasProjection(Plan)?\(" apps packages --type=ts --type=tsx -C3Repository: crs48/xNet
Length of output: 5435
🏁 Script executed:
#!/bin/bash
set -e
echo "## canvas.ts projection plan implementation"
sed -n '1,260p' packages/social/src/projection/canvas.ts
echo
echo "## application of projection and default origin"
rg -n "applySocialCanvasProjectionPlan|applySocialCanvasProjection\\b|SocialCanvasProjectionOptions|origin" packages/social/src packages/views/src apps --glob '*.{ts,tsx}' -C 4
echo
echo "## relevant tests"
sed -n '140,260p' packages/social/src/__tests__/views-lenses-projection.test.ts 2>/dev/null || trueRepository: crs48/xNet
Length of output: 50367
🏁 Script executed:
#!/bin/bash
set -e
echo "## social projection application and tests"
sed -n '1,170p' packages/views/src/canvas-view/social-projection.ts
sed -n '1,180p' packages/views/src/canvas-view/social-projection.test.ts
echo
echo "## query frames placement result"
sed -n '330,450p' packages/views/src/canvas-view/query-frames.tsx
echo
echo "## focused searches for applySocialCanvasProjection and custom origin"
rg -n "applySocialCanvasProjection(Plan)?\\b|\\borigin\\s*:" apps packages --glob '*.{ts,tsx}' --glob '!**/test.*' --glob '!**/*.test.*' --glob '!**/*.md' -C 2 || trueRepository: crs48/xNet
Length of output: 39081
🏁 Script executed:
#!/bin/bash
set -e
echo "## deterministic placement overlap probe"
node - <<'JS'
const DEFAULT_NODE_WIDTH = 260
const DEFAULT_NODE_HEIGHT = 132
const DEFAULT_GAP_X = 96
const DEFAULT_GAP_Y = 72
function createPlan(length, columns, existingBounds = null) {
const selectedNodesLength = Math.min(length, 75)
const effectiveColumns = columns ?? Math.max(1, Math.ceil(Math.sqrt(Math.max(selectedNodesLength, 1))))
const nodes = []
for (let i = 0; i < selectedNodesLength; i++) {
const column = i % effectiveColumns
const row = Math.floor(i / effectiveColumns)
nodes.push({
id: `n${i}`,
position: {
x: column * (DEFAULT_NODE_WIDTH + DEFAULT_GAP_X),
y: row * (DEFAULT_NODE_HEIGHT + DEFAULT_GAP_Y),
width: DEFAULT_NODE_WIDTH,
height: DEFAULT_NODE_HEIGHT
}
})
}
const rowCount = Math.ceil(nodes.length / effectiveColumns)
const bounds = {
x: 0,
y: 0,
width: nodes.length === 0 ? 0 : effectiveColumns * DEFAULT_NODE_WIDTH + Math.max(0, effectiveColumns - 1) * DEFAULT_GAP_X,
height: nodes.length === 0 ? 0 : rowCount * DEFAULT_NODE_HEIGHT + Math.max(0, rowCount - 1) * DEFAULT_GAP_Y
}
return { nodes, bounds }
}
function rectsOverlap(a, b, paddingX = 0, paddingY = 0) {
const ax = a.x - paddingX, ay = a.y - paddingY, aw = a.width + 2 * paddingX, ah = a.height + 2 * paddingY
const bx = b.x - paddingX, by = b.y - paddingY, bw = b.width + 2 * paddingX, bh = b.height + 2 * paddingY
return !(ax + aw <= bx || bx + bw <= ax || ay + ah <= by || by + bh <= ay)
}
const a = createPlan(100)
const b = createPlan(50)
let overlap = false
for (const n1 of a.nodes) {
for (const n2 of b.nodes) {
if (n1.id !== n2.id && rectsOverlap(n1.position, n2.position)) {
overlap = true
console.log(`two different projection plans overlap: ${n1.id} at ${n1.position.x},${n1.position.y} with ${n2.id} at ${n2.position.x},${n2.position.y}`)
}
}
}
let existing = { x: 100, y: 100, width: 120, height: 80 }
for (const n of a.nodes) {
if (rectsOverlap(n.position, existing, 2, 2)) {
console.log(`projection overlaps existing object: ${n.id} at ${n.position.x},${n.position.y} with object at ${existing.x},${existing.y}`)
break
}
}
console.log(a.bounds)
console.log(b.bounds)
console.log('overlapResults', { overlap, existingOverlapFound: existing && rectsOverlap(createPlan(1).nodes[0].position, existing, 2, 2) })
JSRepository: crs48/xNet
Length of output: 3597
Offset social projections before placing them.
createSocialCanvasProjectionPlan lays out cards from (0, 0) and applySocialCanvasProjection defaults origin to that same point. Multiple different projection plans write different ids to the same absolute positions, so they overlap. Apply the projection with an origin that places the whole plan away from existing canvas objects.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/views/src/canvas-view/query-frames.tsx` around lines 437 - 447,
Update applySocialCanvasProjection to compute an origin that places the plan
away from existing canvas objects, then pass that origin to
applySocialCanvasProjectionPlan instead of relying on the default (0, 0) origin.
Preserve the existing empty-plan, undo-boundary, and result behavior.
| export function describeSocialCanvasProjection(result: ApplySocialCanvasProjectionResult): string { | ||
| const parts = [`${result.nodeCount} cards`, `${result.edgeCount} connections`] | ||
| if (result.omittedNodeCount > 0) parts.push(`${result.omittedNodeCount} more not shown`) | ||
| if (result.omittedEdgeCount > 0) { | ||
| parts.push(`${result.omittedEdgeCount} connections not shown`) | ||
| } | ||
| return `Projected ${parts.join(', ')}.` | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Pluralize "cards" and "connections" correctly in the projection summary.
describeSocialCanvasProjection always uses plural nouns regardless of the count. For a single card or connection, the string reads "1 cards" or "1 connections", which is not correct English. The test file encodes this same incorrect text as its expected value, so fixing the implementation requires updating the test in the same change.
packages/views/src/canvas-view/social-projection.ts#L113-L120: pluralize "card"/"connection" based onresult.nodeCount/result.edgeCount.packages/views/src/canvas-view/social-projection.test.ts#L127-L131: update the expected string in'says nothing about omissions when nothing was omitted'to match the corrected singular/plural wording.
✏️ Proposed fix for pluralization
export function describeSocialCanvasProjection(result: ApplySocialCanvasProjectionResult): string {
- const parts = [`${result.nodeCount} cards`, `${result.edgeCount} connections`]
+ const parts = [
+ `${result.nodeCount} ${result.nodeCount === 1 ? 'card' : 'cards'}`,
+ `${result.edgeCount} ${result.edgeCount === 1 ? 'connection' : 'connections'}`
+ ]
if (result.omittedNodeCount > 0) parts.push(`${result.omittedNodeCount} more not shown`)
if (result.omittedEdgeCount > 0) {
parts.push(`${result.omittedEdgeCount} connections not shown`)
}
return `Projected ${parts.join(', ')}.`
}- expect(describeSocialCanvasProjection(result)).toBe('Projected 1 cards, 0 connections.')
+ expect(describeSocialCanvasProjection(result)).toBe('Projected 1 card, 0 connections.')📍 Affects 2 files
packages/views/src/canvas-view/social-projection.ts#L113-L120(this comment)packages/views/src/canvas-view/social-projection.test.ts#L127-L131
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/views/src/canvas-view/social-projection.ts` around lines 113 - 120,
Update describeSocialCanvasProjection to use singular “card” and “connection”
when nodeCount or edgeCount equals one, while retaining plural forms otherwise;
also update the expected string in
packages/views/src/canvas-view/social-projection.test.ts lines 127-131 to match
the corrected wording.
| function readPending(): PendingCanvasLens | null { | ||
| const raw = (() => { | ||
| try { | ||
| return storage()?.getItem(STORAGE_KEY) ?? null | ||
| } catch { | ||
| return null | ||
| } | ||
| })() | ||
|
|
||
| if (!raw) return memoryPending | ||
|
|
||
| try { | ||
| const parsed = JSON.parse(raw) as PendingCanvasLens | ||
| if (typeof parsed?.canvasId !== 'string' || typeof parsed?.viewId !== 'string') return null | ||
| return parsed | ||
| } catch { | ||
| return null | ||
| } | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Validate the shape of projection, not just canvasId/viewId.
readPending only checks that canvasId and viewId are strings. projection is cast through as PendingCanvasLens and passed on unchecked. If the stored shape of SocialCanvasProjectionPlan changes between when a request is parked and when it is claimed (for example, a long-lived tab across a deploy), a malformed projection reaches the canvas-apply path with no signal that it is untrustworthy.
Add a minimal structural check (or reuse a shared validator) for projection before returning it, and drop the pending request when it fails, the same way an unparseable JSON payload is already dropped.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/views/src/data-workspace/pending-canvas-lens.ts` around lines 62 -
80, The readPending function must validate the stored projection before
returning a PendingCanvasLens. Add or reuse a minimal structural validator for
SocialCanvasProjectionPlan, and return null when projection is malformed while
preserving the existing canvasId/viewId checks and valid payload behavior.
| - **The layer commoditised.** Five meta-harnesses landed in roughly one week of | ||
| June 2026 — Databricks Omnigent (Apache-2.0), Zed ACP, Vercel HarnessAgent, | ||
| Cloudflare Flue, and Conductor — on top of two excellent free harnesses | ||
| (Hermes, MIT; OpenClaw). Nothing xNet builds here stays differentiated for a | ||
| quarter. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## files matching llms-full.txt"
fd -a 'llms-full\.txt$' . || true
echo
echo "## target lines"
if [ -f site/public/llms-full.txt ]; then
sed -n '10602,10656p' site/public/llms-full.txt | nl -ba -v10602
fi
echo
echo "## search for related terms in repo"
rg -n "Omnigent|HarnessAgent|Flue|Conductor|Hermes|OpenClaw|xNet|ACD|ACP|meta-harness|harness" site/public || trueRepository: crs48/xNet
Length of output: 283
🌐 Web query:
docs Zed ACP release date definition protocol
💡 Result:
The Agent Client Protocol (ACP) is an open-source standard created by Zed Industries, in collaboration with Google, to enable interoperability between AI agents and code editors [1][2][3]. Release Date and Definition The protocol was introduced by Zed on August 27, 2025, alongside the integration of Google’s Gemini CLI as its first reference implementation [1][2]. ACP is defined as a lean framework that standardizes communication between an editor (the client) and an AI agent (the server) [2][4]. Its primary goal is to prevent vendor lock-in by allowing developers to use their preferred AI agents across any editor that supports the protocol [3][4]. Protocol Specifications ACP facilitates communication through the following mechanisms: - Communication Format: The protocol uses JSON-RPC endpoints to exchange user requests and agent responses [2][4]. - Data Transport: For local agents, the protocol runs as a sub-process of the editor, communicating via JSON-RPC over stdio (standard input/output) [3][4]. Remote agents (work in progress) communicate via HTTP or WebSocket [4]. - Compatibility: ACP reuses specifications from the Model Context Protocol (MCP) where possible while implementing custom types for editor-specific features, such as rendering diffs and syntax highlighting [3][4]. - Licensing: The protocol is open source under the Apache license [1][2]. For official documentation and further technical details, visit the dedicated protocol website at agentclientprotocol.com or the Zed documentation portal at zed.dev/acp [1][4][5].
Citations:
- 1: https://zed.dev/acp
- 2: https://zed.dev/blog/bring-your-own-agent-to-zed
- 3: https://www.theregister.com/2025/08/28/google_zed_acp/
- 4: https://agentclientprotocol.com/get-started/introduction
- 5: https://zed.dev/acp/editor/zed
🌐 Web query:
Cloudflare Flue framework harness wrapping harnesses
💡 Result:
In the Flue framework, the concept of a harness refers to the programmable environment—or agentic loop—that provides an agent with its capabilities, such as tools, sandboxes, sessions, and memory [1][2][3]. A Flue harness acts as the runtime layer that allows a large language model (LLM) to perform autonomous tasks by managing context, state, and interaction with the host environment [1][2]. The term wrapping harnesses refers to how the Flue framework abstracts and encapsulates these complex operations into a unified interface [2][4]. Specifically: 1. Harness Encapsulation: Flue provides a FlueHarness interface [4]. When an agent is initialized, the active runner provides this harness to the agent [4]. Application code does not manually initialize or name these harnesses; instead, they are supplied as an initialized environment (context.harness) to agent actions [4]. 2. Layered Architecture: A harness is composed of various layers—such as sessions for memory, filesystems for data access, and sandboxes for secure code execution [5][3]. Flue wraps these underlying primitives (like Cloudflare Durable Objects or local processes) into a consistent API so developers can focus on defining agent behavior rather than orchestration [1][2]. 3. Platform-Native Wrapping: When deploying to platforms like Cloudflare, Flue wraps Cloudflare's native capabilities—such as the Agents SDK, Durable Objects, and container-backed sandboxes—within the FlueHarness structure [6][1][7]. For example, the cloudflareSandbox function wraps a platform-native sandbox Durable Object, providing a consistent interface for the agent to execute shell commands and file operations regardless of whether it is running locally or on Cloudflare [6][8]. By wrapping these disparate components (tools, storage, compute, and platform-specific primitives) into a single harness, Flue enables developers to create agents that are portable across different runtimes (e.g., Node.js, Cloudflare Workers, or CI environments) while maintaining a standardized way to interact with the environment [1][5][2].
Citations:
- 1: https://blog.cloudflare.com/agents-platform-flue-sdk/
- 2: https://www.developersdigest.tech/blog/flue-agent-harness-layer
- 3: https://writer.mrmehta.in/agent-model-harness
- 4: https://flueframework.com/docs/api/agent-api/
- 5: https://github.com/withastro/flue
- 6: https://flueframework.com/docs/ecosystem/deploy/cloudflare/
- 7: https://github.com/withastro/flue/blob/main/docs/deploy-cloudflare.md
- 8: https://flueframework.com/docs/ecosystem/sandboxes/cloudflare/
🌐 Web query:
Vercel HarnessAgent API running existing harnesses
💡 Result:
The HarnessAgent is part of the Vercel AI SDK (introduced in version 7) and provides a unified interface for running agentic coding harnesses such as Claude Code, Codex, and Pi [1][2]. It is designed to manage the lifecycle of these harnesses, including their sandboxed workspaces, sessions, and tool executions [1][3][2]. To run or resume existing harness sessions using the HarnessAgent, you utilize the createSession method [4][5]. The process generally involves persisting the opaque resume state returned by a session [5]. Key aspects of managing existing/resumable sessions include: 1. Session Creation and Resumption: The createSession method allows you to either start a fresh session or resume from a state previously returned by session.detach or session.stop [4]. 2. Resuming State: To resume, you pass the original sessionId along with the resumeFrom payload (the state obtained from a previous detach or stop) [4][5]. 3. Session Persistence: You should persist the opaque resume state returned by a session when it is detached [5]. The chatId is typically used as the harness sessionId to ensure the sandbox maintains a stable identity across different requests and processes [5]. 4. Example Usage: agent.createSession({ sessionId: chatId, resumeFrom: storedResumeState }); When you are holding a session in memory, you can pass that active session directly to the agent.stream or agent.generate methods to continue interaction within the same context [5][6]. Note: Harness packages are currently experimental, and APIs may be subject to change [2]. Always refer to the latest Vercel AI SDK Harness documentation for implementation specifics [1][2].
Citations:
- 1: https://ai-sdk.dev/docs/ai-sdk-harnesses/harness-agent
- 2: https://vercel.com/changelog/program-agent-harnesses-with-ai-sdk
- 3: https://ai-sdk.dev/docs/ai-sdk-harnesses/overview
- 4: https://github.com/vercel/ai/blob/a23b6767/packages/harness/src/agent/harness-agent.ts
- 5: https://ai-sdk.dev/v7/docs/ai-sdk-harnesses/ui
- 6: https://www.agent-native.com/docs/harness-agents
🌐 Web query:
Databricks Omnigent Apache 2.0 release June 2026
💡 Result:
Databricks officially introduced and open-sourced Omnigent on June 13, 2026, under the Apache 2.0 license [1][2][3]. Omnigent is a meta-harness designed to sit above existing AI coding agents—such as Claude Code, Codex, and custom YAML-defined agents—to provide a unified layer for composition, governance, and collaboration [1][4][3]. Key features include: - Governance and Security: It provides stateful, contextual policies (such as spend caps and risk-based escalation) and OS-level sandboxing (using bubblewrap or seatbelt) to secure agent interactions [4][2][3]. - Multi-Agent Orchestration: It allows users to swap or combine different agent harnesses without requiring code rewrites [3][5]. - Collaboration: It supports live, shared sessions across various interfaces, including terminal, web, desktop, and mobile [3][6]. As of its release, Omnigent is classified as an alpha project [1][2][3]. While Databricks announced its availability and open-source status in mid-June 2026, it is not yet considered an enterprise-ready product with SLA guarantees or SOC 2 certification [2][3]. Users can install it via standard package managers (e.g., pip install omnigent) or access the source code on GitHub [4][5][7]. Additionally, Azure Databricks release notes from June 17, 2026, confirmed that Omnigent was available in Beta within the Azure Databricks ecosystem [8].
Citations:
- 1: https://www.databricks.com/blog/introducing-omnigent-meta-harness-combine-control-and-share-your-agents
- 2: https://advancedai.com/briefings/databricks-omnigent-multi-agent-governance-2026/
- 3: https://www.marktechpost.com/2026/06/13/databricks-open-sources-omnigent-a-meta-harness-that-composes-governs-and-shares-ai-agents-across-claude-code-codex-and-pi/
- 4: https://www.heise.de/en/news/Meta-Harness-for-AI-Agents-Databricks-Releases-Omnigent-as-Open-Source-11335496.html
- 5: https://github.com/omnigent-ai/omnigent
- 6: https://omnigent.ai/
- 7: https://pypi.org/project/omnigent/0.5.1/
- 8: https://learn.microsoft.com/en-us/azure/databricks/release-notes/product/2026/june
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## target lines with Python numbering"
python3 - <<'PY'
from pathlib import Path
p = Path("site/public/llms-full.txt")
lines = p.read_text().splitlines()
for i in range(10602, 10657):
print(f"{i}: {lines[i-1]}")
PY
echo
echo "## related terms in target file"
rg -n "Omnigent|Zed|ACP|Vercel|HarnessAgent|Cloudflare|Flue|Conductor|Hermes|OpenClaw|xNet|meta-harness|harness|June 2026" site/public/llms-full.txt || trueRepository: crs48/xNet
Length of output: 24078
🌐 Web query:
site public llms-full.txt omnigent zed a c p vercel harness agent cloudflare flueConductor Hermes OpenClaw
💡 Result:
The terms listed are components, tools, and protocols within the evolving ecosystem of AI-powered agent orchestration and documentation, particularly focusing on how AI models access context and interact with systems [1][2][3][4]. llms-full.txt This is an industry-standard companion file to llms.txt, containing the full, concatenated Markdown content of a documentation site [5][4]. While llms.txt provides a lightweight table-of-contents index, llms-full.txt serves as a comprehensive "book" that AI models and coding agents can ingest in a single request, avoiding the need for repeated page crawling [5][6][4]. Major platforms like Vercel, Cloudflare, and Nous Research provide these files to optimize their documentation for agent-friendly consumption [7][8][9][10]. Omnigent Omnigent is an open-source meta-harness framework designed to orchestrate various AI coding agents (such as Claude Code, Codex, Hermes, and Cursor) under a unified layer [2][11]. It allows users to swap or combine harnesses, enforce security policies (via sandboxing and pre-tool hooks), and collaborate across different environments (terminal, web, and native apps) without rewriting agent code [2][11][12]. Harness & Agent In this context, a harness defines the operational loop and control logic for an AI agent—how it calls models, selects tools, handles output, and decides when a task is complete [8][2]. Omnigent acts as a meta-harness, managing these underlying agent harnesses (like the Hermes Agent or ACP-based harnesses) to provide uniform policy enforcement and session management [11][12][3]. Protocol terms (ACP, MCP, Zed, Vercel, Cloudflare) - ACP (Agent Client Protocol): A standard communication protocol for agent-client interactions [3]. Omnigent includes a generic ACP harness to connect with any agent speaking this protocol (e.g., Goose, specific Zed integrations, or custom in-house agents) [3]. - MCP (Model Context Protocol): A framework that connects AI assistants directly to external data sources, tools, and servers [7][13]. It is often used to bridge agents with specific capabilities, such as the OpenClaw orchestrator or Omnigent-managed tools [13][3]. - Platform Contexts: Tools like Zed (a code editor), Vercel, and Cloudflare are cited as environments or platforms where these documentation standards (llms-full.txt) and agent protocols (MCP) are actively implemented to facilitate AI-assisted development [7][8][13]. Other projects (Hermes, OpenClaw, flueConductor) - Hermes Agent: An agent framework often integrated into orchestration tools like Omnigent or supported via dedicated harnesses [2][12]. - OpenClaw: A project that provides tools for agent orchestration, often using MCP servers (like clawo-mcp) to expose its capabilities to hosts like Zed, Claude Code, and Continue [13]. - flueConductor: While less documented as a standalone major standard, the context suggests it is part of the ecosystem of specialized tools or agents designed for orchestration and workflow management within these agent-first environments [1][2].
Citations:
- 1: https://github.com/pumblus/okf-harness/blob/main/llms-full.txt
- 2: https://github.com/omnigent-ai/omnigent
- 3: feat(acp): generic ACP harness + Omnigent-tool MCP bridge for all ACP harnesses omnigent-ai/omnigent#2152
- 4: https://dev.to/lab451/llmstxt-vs-llms-fulltxt-whats-the-difference-2026-3lhl
- 5: https://llmtxt.info/llms-full-txt/
- 6: https://www.mintlify.com/blog/the-value-of-llms-txt-hype-or-real
- 7: https://vercel.com/docs/agent-resources
- 8: https://developers.cloudflare.com/agents/llms-full.txt
- 9: docs: publish llms.txt and llms-full.txt for agent-friendly ingestion NousResearch/hermes-agent#18276
- 10: https://developers.cloudflare.com/llms-full.txt
- 11: https://omnigent.ai/
- 12: feat(harness): add Hermes Agent harness with policy enforcement omnigent-ai/omnigent#1132
- 13: https://github.com/Enderfga/claw-orchestrator/blob/main/skills/references/mcp.md
🌐 Web query:
Conductor meta-harness agent June 2026 release
💡 Result:
There was no specific release named "Conductor meta-harness agent" in June 2026. Instead, "Conductor" and "meta-harness" are distinct concepts and tools that gained significant attention during that month [1][2]. Conductor is a closed-source macOS desktop application developed by Melty Labs [1][3]. It is a tool for orchestrating coding agents (such as Claude Code, Codex, and Cursor) in parallel by creating isolated git worktree workspaces for each agent [1][3]. While it was active and reviewed in June 2026, it is categorized as a "meta-harness" tool because of its role in managing multiple agents, but it did not have a specific "meta-harness agent" release [1][3]. "Meta-harness" refers to a new architectural layer in AI agent systems that sits above individual agent CLIs to provide governance, interoperability, and orchestration [1][4][5]. The term gained prominence in June 2026 following several industry events: * Databricks open-sourced Omnigent, a meta-harness, on June 13, 2026, which explicitly popularized the "meta-harness" framework [1][2][5]. * Vercel introduced HarnessAgent in AI SDK 7 on June 12, 2026 [1][2]. * Other tools and protocols like Zed's Agent Client Protocol (ACP) and Cloudflare's Flue also emerged or saw updates during this same window in June 2026 [1][2]. * These industry developments followed an earlier academic paper, "Meta-Harness: End-to-End Optimization of Model Harnesses," published in March 2026, which introduced an outer-loop system for searching and optimizing agent harness code [2][6]. In summary, Conductor is a specific desktop application for managing parallel agents, while "meta-harness" is an industry-wide concept for an orchestration layer that saw a surge in tools and definitions in June 2026 [1][2][3].
Citations:
- 1: https://codepick.dev/en/guides/meta-harness-2026/
- 2: https://pub.towardsai.net/what-is-a-meta-harness-in-ai-2af40e788c2e
- 3: https://dev.to/agentiknet/9-coding-agent-orchestrators-honestly-compared-dated-sourced-and-one-of-them-is-mine-3kpk
- 4: https://www.developersdigest.tech/blog/omnigent-meta-harness-agent-orchestration
- 5: https://www.databricks.com/blog/introducing-omnigent-meta-harness-combine-control-and-share-your-agents
- 6: https://arxiv.org/html/2603.28052
Correct the ADR examples before publishing.
Split the list by layer, or use only projects at the same composition layer. The current list mixes meta-harness examples with Zed ACP, a September 2024 protocol specification.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@site/public/llms-full.txt` around lines 10626 - 10630, Update the ADR passage
in the “The layer commoditised” section to remove Zed ACP from the meta-harness
examples or separate it into an appropriate protocol-layer list, ensuring every
project grouped together belongs to the same composition layer before
publication.
| "title": "Your imported social library is now legible, projectable, and searchable by transcript", | ||
| "summary": "Imported TikTok favourites and collections get their own feeds, every surface now shows real titles and thumbnails instead of platform ids, a saved lens can be projected onto the canvas as cards with the connections between them, and YouTube transcripts can be fetched per import run so an AI agent can search what was actually said in videos you saved.", |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Document the existing-database index migration.
The entry promises transcript search for imported libraries. The exploration record states that existing databases require rebuildFTS() before previously stored rows enter nodes_fts. Add an upgrade note, or trigger the rebuild during migration, so existing users do not see empty search results after updating.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@site/src/data/changelog/2026-08-01-your-imported-social-library-is-now-legi.json`
around lines 4 - 5, Update the changelog entry around the title and summary to
document that existing databases must run the nodes_fts rebuild migration via
rebuildFTS() before transcript search includes previously stored imported rows;
alternatively, wire rebuildFTS() into the applicable migration path so the
upgrade performs it automatically.
…orters The shared enrichment hook imported the @xnetjs/social root barrel, which re-exports every platform importer; reddit.ts reaches for @xnetjs/data/database, a subpath the Storybook build aliases straight into a file path. Importing through ./enrichment, ./schemas and ./projection keeps the importers out of any consumer that only needs enrichment or a projection type. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
🖼️ UI changes in this PRComponentsScreensAuto-captured by CI · run. Informational — not a blocking check. |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
…into claude/0419-social-graph-atlas
The hub-address work on main added useResolvedHubUrl, ResolvedHubUrl, HubAddressConfig and XNetConfig.hubAddress without regenerating the reports, so the drift check failed on any branch that merged it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>









Implements exploration 0419 — The Social Graph Atlas (16/19 items; 13/13 implementation, 3/6 validation).
The exploration's finding was that the vision — imported social data as a navigable graph, renderable as a feed, timeline or canvas, and readable by an AI agent — was roughly 80% built already. This is the wiring, plus the one genuinely new capability.
What landed
Transcripts (the new capability). No archive ships them and the official caption APIs only serve videos you own, so
packages/social/src/transcripts/adds aTranscriptFetcherseam with a device-local YouTube implementation. The unofficial caption endpoint is IP-blocked from datacenter ranges and is not blocked from the machine the user watches on — which is why this deliberately does not go through the hub. Transcripts land as linkedSocialContentnodes (contentKind: 'transcript'), segmented on cue boundaries so nothing is truncated to fit a field cap. Every attempt ends in exactly one of four outcomes, and "no captions exist", "we were refused" and "we have not looked yet" stay three different values.Canvas projection.
createSocialCanvasProjectionPlan()was built and tested but called from no app. The apparent duplication withcreateSavedViewCanvasProjectionNodesturned out to be a pair, not a redundancy — one extracts nodes from previews, the other lays them out with edges. They now compose, andapplySocialCanvasProjectionPlan()writes the result onto a canvas doc. The web app reaches parity with Electron via a parked-request handoff across the route change.Enrichment. Moved out of
apps/webintopackages/social+packages/views, so the desktop app stops rendering imported feeds as a wall of opaque platform ids. TikTok now resolves through its own oEmbed endpoint directly from the client — the one platform that sends CORS headers, and therefore the only one that works with no hub at all.Feeds and agent scope. TikTok videos and collections get feed seeds; a cross-platform activity timeline opens on the time axis. A social retrieval scope bounds what an agent may read — DMs, conversations and search history are excluded by default and widening is an explicit, visible call.
Bug found while validating
extractSearchableContentreadcontent,description,body,nameandnote— but notsearchText, the property 22 importer call sites denormalize full text into precisely so it can be searched. Every imported post, comment and video transcript was absent fromnodes_ftswhile the pipeline reported it as indexed: search returned a clean empty result rather than an error. Fixed, withtextPreviewas fallback. Existing databases needrebuildFTS()to pick up already-imported rows.Verification
pnpm typecheck— 101/101 taskspnpm test— 11,861 passed, 0 failedpnpm build— 57/57 taskspnpm lint— 0 errors;prettier --checkcleancheck:api-report,check:ai-retrieval,check:agent-docs,check:view-drift,check:electron-parity,check:humane-patterns— all passpackages/social, plus canvas-projection and FTS-extractor suitesLeft open, deliberately
Three validation boxes need inputs this pass could not produce, and are documented in the doc rather than checked off: real YouTube/Instagram/TikTok archives (boxes 1–2) and a live agent session (box 4). The transcript box is checked on a 50-target pass with the transport stubbed — the accounting invariant is verified, a live network run is not.
🤖 Generated with Claude Code
Summary by CodeRabbit