| Name | Modified | Size | Downloads / Week |
|---|---|---|---|
| Parent folder | |||
| README.md | 2026-10-07 | 58.9 kB | |
| v0.13.0 source code.tar.gz | 2026-10-07 | 196.6 MB | |
| v0.13.0 source code.zip | 2026-10-07 | 207.0 MB | |
| Totals: 3 Items | 403.6 MB | 0 | |
Core/SDK 0.13.0 (2026-10-07)
Minor Changes
- Chats can run on a coding agent other than Composer's own.
SessionConfiggainsharness(which agent runs the chat) andhost(the device that runs it). Plugins register agents throughAssistantCapabilities.Agent, and the agent service picks the turn engine per chat from it.MakeTurnProducerOptionsnow includes thechat.
plugin-code adds the desktop app's agent helper and an ACP turn engine. It streams the agent's transcript into the chat, keeps the agent's session warm between turns and resumes it after a restart. plugin-claude uses it to offer Claude Code on the user's machine.
An agent's permission requests arrive as a request content block (ContentBlock.Request). The chat renders it as a card, and the answer goes back through AssistantOperation.RespondToRequest.
ProjectOperation.DelegateTaskToChat takes an optional harness. Without one, it uses the new defaultAgent assistant setting while that agent is available, and Composer otherwise. A task's menu lists an "Assign to" entry per registered agent and disables those that cannot run on this device. To support this, ObjectAction gains group and unavailable.
A project overview has a settings slot, ProjectView.Settings, where other plugins add settings. plugin-code uses it for the project's repository folder on this device, and a delegated chat works in its own git worktree of that folder.
A coding agent gets Composer's operations as the composer MCP server, scoped to its chat's space. The page serves the same surface as dx mcp serve, and the agent helper relays the agent's requests to it.
CodeAgent.make takes sessionMeta, agent-specific ACP session options built from the Composer tools on offer. Claude Code uses it to call Composer's read-only tools without asking each time. The Claude plugin now depends on the Code plugin, which runs the agent helper. (3e73e53)
- Add
@dxos/plugin-agent, an agent that talks to people through any channel, remembers them as ECHO objects, reads every conversation turn into facts, relays messages, and keeps one-time and ongoing ("keep me posted") watches whose updates it writes from the conversation's context. Every subpath of the package is a namespace:AgentStateandAgentKnowledge(each with aRootcontainer), one per skill (ConversationSkill,GoalsSkill,InterviewSkill,ModesSkill,NoteTakerSkill,RelaySkill), and one per type and operation set.
@dxos/plugin-thread channel backends can now open direct conversations (openDirect), post into threads (threads.send), run a connection (connection.start/stop/status), and return a send receipt. New operations sendToChannel, openDirect, connectChannel, disconnectChannel and getChannelStatus dispatch to them, and the handlers are published as the ThreadOperationHandlerSet subpath. The Discord and Slack plugins implement these backends.
An agent prompt can name its sender: AgentProcess accepts { prompt, sender?, properties? } as well as a bare prompt (AgentInput, makeInputMessage), AgentService.Session.submitPrompt and the assistant's request and session take a sender, and the model sees a named sender as [From: <name>]. useChatProcessor and AiChatProcessor take a sender, and ChatThread takes a userHue.
Agent.loadChat no longer picks a chat bridged from an external conversation as the agent's primary chat, and finds chats with a child-of filter so it also works on EDGE. Agent.makeInitialized accepts a skill ref, and Skill.makeRef binds a database skill as-is and any other by registry URI.
The ProfileOf relation moves from @dxos/plugin-crm to @dxos/types with its typename unchanged, so existing profiles still resolve. EdgeHttpClient.request makes an authenticated call to any EDGE route. pipeline-rdf exports DEFAULT_MODEL. FormInlineAnnotation now survives the JSON-schema round trip. A plugin that declares two modules with the same id now fails when it is constructed instead of silently dropping one. (246ee3c)
-
Cloudflare's Clef decision models are in the catalog:
Model.cloudflareClefandModel.cloudflareClefFlashanswer through the same Workers AI route asModel.cloudflareJev, andModel.decisionModelslists every decision model.Model.defaultDecisionModelis an alias a resolver swaps for the configured default;TypeSafeResolver.maketakes it asdefaultModel(jev on TypeSafe when unset), and the TypeSafe plugin sets it from its new Default decision model setting. (1b2e9f3) -
Decisions can carry images for models that read them.
DecisionModel.decide(definition, { input, images })reaches Clef and Clef Flash as embedded data URLs on the System Oneimagesextension; jev, which reads no images, fails such a call withInvalidUserInputErrorrather than answer blind.TypeSafeResolver.makeDecisionModeltakesimages: trueto opt a back-end in, and the resolver sets it from a model'simagecharacteristic. Effect'sDecisionModelgainsimagesthrough a local patch until the upstream change lands.
@dxos/diagram gains a rule library of what makes a diagram read well (rules/DIAGRAM.mdl, parsed by Rules), scored by Appeal: rules measurable from geometry are scored in code, and the rest are asked of a judge shown the rendered page (Architecture.judge and Aesthetics.judge accept a subject with images). Appeal.objective() lets the layout engine choose by appeal. DxSvg embeds a JSON payload in an SVG's <metadata>, so a drawing exported as .dx.svg opens as an image anywhere and imports back as editable objects.
The mermaid layout engine draws tidier diagrams: ports along each box side follow the order their connectors turn away (Ports), parallel runs that share a line are nudged apart (Nudge), and placements are compacted toward the boxes they connect. On the illustrator's corpus, crossings fall from 56 to 23 and no connectors overlap; compiling takes longer because each candidate is re-routed. (5a27d5c)
- The roots of
@dxos/app-framework,@dxos/app-graph,@dxos/app-toolkit,@dxos/assistant-toolkit,@dxos/compute,@dxos/effect,@dxos/graph,@dxos/observabilityand every plugin now export namespaces only, and every namespace has its own subpath: import it withimport * as Hooks from '@dxos/app-framework/Hooks'and callHooks.useOperationInvoker(). A compound component exports its parts (<ObjectCard.Root>,<ObjectCard.Header>), a single component keeps its own name (<TracePanel.TracePanel>), and errors live in the namespace that owns them (Operation.NoHandlerError,Capability.NotFoundError,ConnectorSync.DatabaseMissingError) or in a<Domain>Errormodule (FunctionsAiError,ConnectorError).
Breaking: names that were exported flat from a root moved into namespaces, e.g. ProcessManagerPlugin.make(), PluginManager.Context, PluginManifest.DEV_SERVER_PORT, Progress.makeTraceSink, SpaceSurface.RENAME_POPOVER, Calendar.getRangeSelectionId, AgentSkill.Handlers, SlashCommand.resolveSlashCommand, SelectionModel.SelectionModel, HaloServices.layer, PluginStorage.loadPlugins, CorePlugins.make(), KvsStore.make (formerly createKvsStore), CardSlot.IconSlot and CardSlot.MenuSlot (formerly CardIconSlot and CardMenuSlot), Hooks.useUpdateRow in @dxos/app-toolkit and OtelTracer.make/OtelTracer.layer in @dxos/effect; a plugin's meta is <Name>Plugin.meta. Flat names nothing imported outside their package are no longer exported. @dxos/compute/Errors is removed, @dxos/app-solid no longer re-exports @dxos/app-framework, and @dxos/util/Position is a subpath.
HomeSection and NamePopover move from @dxos/app-framework to @dxos/app-toolkit (@dxos/app-toolkit/HomeSection, @dxos/app-toolkit/NamePopover), so app-framework no longer depends on @dxos/react-ui. A check-module-structure guard fails if any app-framework export reaches react-ui again. (9ab98cd)
-
Add
activateHeadlessPluginsto@dxos/app-toolkit/testing, which activates plugins without a UI (as the EDGE operation-service does) and reports activation failures plus the operation keys and schema typenames they contribute. Headless hosts such as workerd no longer activate modules that need an app-only capability: the assistant's question resumer, and the sheet's compute-graph registry and markdown extension, are now node-only. (69a4a85) -
NativePasskey.getPasskeySupport()now reports'native'in the Composer iOS app, which creates and redeems passkeys through its own AuthenticationServices bridge, and'none'when that bridge is missing, never WebAuthn.createNativePasskeyandloginNativePasskeyinvoke whichever bridge the shell names. New:NativePasskey.isNativePasskeyError()recognises the iOS bridge's structured rejection, soPasskeyErrortreats only a dismissed sheet as a dismissal and reports every otherASAuthorizationErroras a failure.
@dxos/util's storage cleanup helpers (clearServiceWorkers, clearCaches, clearOPFS, clearIndexedDB) resolve where their API is absent, as in a WKWebView on a custom scheme, instead of throwing. (e99ee70)
-
Composer links now carry a
?title=parameter naming the object they open — in the address bar (kept in step with the attended plank) and in "Copy link" — so messenger previews can name the object.UrlPath.withTitlein@dxos/app-toolkitbuilds it. (ff92c50) -
NativePasskey.getPasskeySupport()replacessupportsNativePasskeys()and returns'native','web'or'none'. The macOS desktop app reports'none'unless its shell confirms that its signed identity can complete a passkey request, so builds that can't finish one no longer offer passkeys or hang on an empty system sheet. Breaking:supportsNativePasskeys()is removed. (8fc641a) -
client.halo.inboxrelays signed messages of any type between identities (messages,sendMessage,ack, and astatusthat readsaccount-requiredwhen EDGE refuses an identity with no account), and space invitations now travel as inboxMessages rendered by theorg.dxos.role.spaceInvitationsurface.SpaceOperation.AddMembersreports members it admitted but could not notify innotNotified, deck companions can show a rail-tab count viaAppNode.makeDeckCompanion({ badge }), andCardTile/Card.Rowplace leading cells in the start rail. Breaking:inbox.notices,inbox.sendanduseInboxNoticesare removed (useinbox.messages,inbox.sendMessageanduseInboxMessages), as are plugin-client's invitation toast, invitations list and account badge. (8980a93) -
Agents gain a brain: each member talks to an agent in their own private chat, the agent records facts from every turn in an RDF fact store and watches them against the goals people set, and a matching fact wakes the requester's chat with an update, relayed as a synthetic system note. The brain runs in memory locally and as a SQLite Durable Object on EDGE. Fact extraction now works with Anthropic structured output, and
@dxos/computeaddsProcess.EnvironmentService, andProcess.currentEnvironment. (bbe9f18) -
Process definitions are now durable operations:
Process.make→Operation.makeDurable,Process.Process→Operation.Durable,Process.Callbacks→Operation.DurableHandler,Process.ProcessContext→Operation.DurableContext, andBaseServices/ChildEventmove toOperation.Process.fromOperationmoves to@dxos/compute-runtimeasDurableOperation.fromOperation. TheProcessname now means a running process:Process.Info→Process.Process. (68dc875) -
Process.Manager(Process.ManagerService) replacesProcess.Monitor: it keeps the process-tree reads and trace stream that span local and remote runtimes, and addsspawnandhandlesverbs that take aProcess.Location, so a caller no longer holds the local and remote managers separately.Process.isTerminalandProcess.isExitedreplace hand-written checks of terminal process states.
Breaking: Process.Monitor, Process.MonitorFilter and Process.ProcessMonitorService are removed (use Process.Manager, Process.Filter, Process.ManagerService); ProcessManager.Handle, Status, SpawnOptions and ListOptions move to Process; ProcessMonitor.layer is now UnifiedProcessManager.layer; the local manager exposes processTreeAtom and subscribeToTraceMessages directly instead of monitor; the Capabilities.ProcessMonitor capability is now Capabilities.ProcessManager; and AgentService.layer requires Process.ManagerService instead of both process managers. (596728d)
-
Add
SqlService: operations and processes declare it and callSqlService.database({ name })for an EffectSqlClient, includingwithTransaction. Locally it runs on the client services host, which rejects statements that touch SQLite internals, host tables or another database's tables, and connection-level commands such asPRAGMAandATTACH. (dde8f43) -
Add
@dxos/datalog, a dependency-free Datalog engine (parser, static checks, incremental stratified semi-naive evaluation with provenance, aggregates and pluggable built-ins) that runs in the browser, workerd and Node, and@dxos/brain, which encodes pipeline-rdfRDF.Facts directly as Datalog relations and evaluates compiled goal rules: canonical-vocabulary shorthand, theabout/concerns/ time built-ins, and wakes on new bindings, first achievement and sub-goal status changes.@dxos/pipeline-rdfnow preserves a fact's illocution (force, mood, addressee) through the fact store, and exports its RDF vocabulary, fact ↔ triples mapping and predicate normalizer asRDF.Vocab,RDF.MappingandRDF.Predicate, which@dxos/brainuses to canonicalize predicates.
Breaking (@dxos/pipeline-rdf): RDF.Term is now a discriminated union tagged by kind — { kind: 'entity', entity, label? } or { kind: 'literal', literal } — so ECHO can store facts as they are. Code that builds terms must add kind, and code that narrows with 'entity' in term should switch on term.kind; RDF.termValue returns a term's join key. The RDF triple form is unchanged, so facts already in a FactStore read back with the tag. RDF.Fact gains an optional pass (extraction pass id, serialized as sx:pass). plugin-agent's FactEntry (0.2.0) now holds one RDF.Fact unchanged per feed item, keyed by the fact's id, and a new ExtractionPass item closes each extraction pass (its id is each fact's pass); the ReadSource operation returns pass in place of entry. Entries written as 0.1.0 are no longer read, so chats are re-read from the start. (fc34fb8)
-
MermaidEnginelays out diagrams several times faster: the edge router's search uses typed arrays and an arrival-aware turn estimate, and candidates whose inheritance bus would draw nothing are no longer routed twice. Routes keep their optimal cost, though ties between equal-cost routes can now resolve differently. A newemitCandidateoption, withemitJob, lets a caller route candidates on worker threads. (234ef9c) -
Edge labels sit beside their own route and off group frame borders. The semantic DSL gains soft sides (
A:~left), group shape (compact,max-width=N,diagram aspect=W:H) and fan-in buses (edge A, B -> C bus), and warns about a bus it cannot honour or a group frame an outside relation stretches. Diagnostics measure bound arrows as drawn, count a bus as one connector, and no longer count T-junctions or self-loops as crossings. Node labels wrap, shrink or ellipsize to stay inside their box, and re-rendering a source gives a byte-identical.dx.svg. (014996b) -
When several connectors share one side of a box, the most significant relationship takes the centre of that side: inheritance and implementation first, then composition, then aggregation and the one-to-many and many-to-many relations, then plain associations, then dependencies.
Semantic.significanceexposes the ranking. (22adb53) -
The diagram DSL gains a semantic layer:
diagram,group,nodeandedgestatements describe what is related and roughly where, andDsl.compileplaces and routes the rest. Constraints range from loose to exact —right-of,above,same-row(soft with~), grid cells, absolute positions, port sides,viawaypoints and sharedbuschannels — so a model can write a good-looking diagram directly, without a helper script.
Edges name UML and ER relationships — extends, implements, composes, owns, depends-on, one-to-many, many-to-many — and the renderer draws their line endings (hollow triangle, filled and hollow diamond, crow's foot, dashed lines). Children that extend or implement the same parent sit on one row and meet it through a single trunk and triangle. Mermaid class and ER diagrams carry the same relations through. The illustrator's Constraints story shows each diagram beside its DSL and scores.
The illustrator's render-diagrams task renders .dx sources as well as mermaid, writes a PNG beside each file it is given, and runs from source again. (2550779)
@dxos/aiexposes the chat-completions language-model adapter at its own entry point,@dxos/ai/chat-completions. The adapter depends on nothing buteffectand is what speaks Ollama's and LM Studio's dialects, but until now it was reachable only through theresolversbarrel, which pulls in the DXN-keyed resolver machinery a consumer of the adapter alone has no use for. No behaviour change for existing consumers of@dxos/ai/resolvers.
The subpath is kebab-case on purpose: dxos-subpath-exports engages as soon as a package declares
one PascalCase subpath, and it would then report every namespace in this package's unmigrated root
barrel — flagging the migration rather than a defect. (32f32a0)
-
The project timeline (Gantt) draws its chart again beside the lane names, and its panel scrolls vertically with a thin scrollbar when the lanes outgrow it. An object card's title is one truncated line by default (pass
linestoObjectCard.Headerto clamp to more), and the card popover is only as tall as its content rather than at least--spacing-card-min-height. (3672aff) -
The project timeline is two columns: lane names and the chart. A lane's token and tool counts move into a hover card over its name, and a new
Gantt.LegendTogglebeside the axis switch shows the counts in that column instead (legend/onLegendChangeonGantt.Root, persisted with the project view). The chart scrolls both ways in one area with the horizontal scrollbar at the panel's foot, and is keyboard-navigable: clicking a node focuses the chart, the arrow keys move between lanes and along the timeline, and Space toggles the node's card (Enter selects it). A parent task's bar no longer starts after its sub-tasks'. In a flat deck, a plank's breadcrumbs show its place in the tree (e.g. a session's project and Sessions branch) rather than the navigation history.
Breaking: Gantt.Meta is removed (its content is the legend's hover card and stats mode), and Gantt.Chart's ref is now the svg element. (2f95d25)
- UI layout primitives get simpler, typed APIs; heavy components move into their own packages; and the chat bounds what an agent can queue or spend on its own.
Breaking:
Grid'scolsandrowstake typed track tokens instead of raw CSS:'fill'(a flexible track that may shrink below its content), a number (a share of the free space, also shrinkable),'min'/'max'/'auto'(sized to the content), or a length such as'18rem'orvar(--…). A count is that many equalfilltracks, andgrownow defaults tofalse.Spinneris now an interface (SpinnerProps, with anActivityStateof'ready' | 'thinking' | 'alert' | 'error') with two implementations:ShapeSpinner, the morphing square (its states werepulse/spin/flash), andPulseSpinner, a dot matrix. Import spinners from the root of@dxos/react-ui-components, whose./Spinnersubpath is removed.QueryEditor,QueryFormanduseQueryBuildermove to the new@dxos/react-ui-query(translations at@dxos/react-ui-query/translations), andHtmlwith its colour-scheme and email transforms moves to the new@dxos/react-ui-html, so@dxos/react-ui-componentsno longer carries CodeMirror,@dxos/echo-queryor DOMPurify.Matrixmoves to@dxos/react-ui-experimental.- The
dx-fullscreenutility is renameddx-cover(absolute inset-0): it covers the nearest positioned ancestor, not the screen. ScrollArea.Roothides its overlay thumbs until the pointer is over the frame (autoHidedefaults totrue).
Fixes and behaviour:
- A popover whose content mounts after it opens (the chat thread outline's card) is positioned beside its anchor instead of the viewport's top-left corner.
- The chat prompt takes at most three prompts queued behind a running turn (
maxQueue), on every submit path; queued prompts are small, right-aligned rows flush with the status chip. -
An agent may wake itself with alarms at most
Alarm.MAX_SELF_WAKES(10) times in a row without a user prompt; each wake-up prompt states how many remain, a later alarm is dropped without a turn, and the chat status shows the count beside the next wake time. (7715216) -
@dxos/react-uiis rebuilt on Ark UI primitives styled by plaindx-*component CSS, and every UI package and plugin renders on it; the former component APIs are removed. -
Components are exported flat by name (
Button,Toolbar,Card,Panel,Container,Field,Input,Combobox,Menu,Tabs,Main,Splitter,Toast,Tour,Banner,Empty, …) and sized bydata-sizescopes (xs–xl;Sizeis that scale).Containerlays out rails and subgrids,ControlFrameframes a control with adornments (Input copyable,variant='mono'), anduseMainLandmarkdeclares the app's focus areas (Tab and Arrow Left/Right move between them).Comboboxadds a trigger mode, option descriptions, a create row and async results.Labelis no longer public (useField.Label), and the flow helper isMatch(Match.Root/Match.Case). @dxos/react-ui-listprovidesListbox,OrderedListandTree(virtual rows, drag and drop, disclosure animation);@dxos/react-ui-formprovidesForm(Root,Viewport,Content,Fields,Actions, …),ObjectProperties,ObjectPicker,ViewEditorandRefEditor;@dxos/react-ui-menurendersActionToolbarandActionMenuon the new Toolbar and Menu;@dxos/app-toolkitadds theObjectCardcomposite.@dxos/ui-themerenames the text tokens to--color-fg/fg-muted/fg-subtle(text-fg,text-fg-muted,text-fg-subtle; Typography and Icontone='muted' | 'subtle') and--color-subdued-separatorto--color-separator-subtle, adds--color-focusfor the keyboard focus ring, and derives the control fill from one offset off its host surface in both themes.@dxos/echoaddsAnnotation.ArrayPresentationAnnotation(ordered,display: 'tag' | 'title') for reference arrays;@dxos/effectSchemaEx.getPropertieskeeps an annotated optional field's annotations;@dxos/ui-editormarkdown tables keep empty cells;@dxos/plugin-markdownmarksDocument.descriptionas markdown, and the rename popover shows an object's properties.
Breaking: the former @dxos/react-ui component APIs and the transitional Next namespace are gone; import components
from @dxos/react-ui by name and use the renamed theme tokens. (1737cad)
- The selection companion stacks the selected objects as plain cards in one scroll area with a small gutter, and its "No objects selected" banner sits in the same column, where the first card would. A form's nested object shows its label and disclosure above the bordered group of its fields rather than inside it.
Banner.Roottakesinsetto override its own gutter, for a host that already pads it.
Breaking: Instructions no longer has a description field (nothing read it), and Instructions.make no longer accepts one. (3022878)
-
Task lists, trees and the chat prompt are reworked on the react-ui components.
-
Task list rows and the task editor place their cells by column name on one shared template, so the editor's fields, pickers and cancel sit in the rows' columns. The editor creates with an estimate and a priority, saves from an end adornment on its title field, and always takes the list's grid.
TaskList.Rootaddsflush,showAssigneesandshowMnemonics; the leading column holds one reference button that shows the ordinal and copies the task's URI.TaskPropertiesandTaskHistoryare top-level components, and the task's reference headsTaskProperties. - Breaking:
Gridno longer grows by default (passgrowto fill and clip its parent), matchingFlex.TaskEditorandTaskOrdinalare removed (the task article renders a form over theTaskschema, whose description is Markdown),TaskMnemonicis no longer exported, andTaskList.EditordropsgridandshowControls. Tree.Contenthas no gutter by default and pads row ends (rowInset), so row highlights run edge to edge under an overlay thumb. A deferredActionMenukeeps the focus an outside click moved;ActionToolbartakes astartslot.Form.RoottakesmarkdownExtensions. Popup options sit in an equal inset, an emptySelectopens no popup,Select.Triggertakesfixed, a splitter drag no longer dims its panes, and clickable tags keep their hue's text colour.-
Surface modules in plugin-client, plugin-preview and plugin-file declare every role they bind. (a449958)
-
The EDGE WebSocket now advertises the client's SDK version, sent as a
dxos-version.<semver>entry inSec-WebSocket-Protocol(prefixEDGE_CLIENT_VERSION_PROTOCOL_PREFIXfrom@dxos/protocols), so EDGE can tell which builds are connecting. (fe08304) -
Every
@dxos/react-uicomponent family is now a namespace module with its own subpath. A compound family exports its parts:import * as Dialog from '@dxos/react-ui/Dialog'givesDialog.Root,Dialog.ContentandDialog.RootProps. A single component keeps its own names:<Icon.Icon>,Icon.IconProps. Related components share a namespace:Button(Button.Root,Button.Toggle,Button.Menu,Button.Group),Input(Input.Root,Input.Textarea,Input.Number,Input.Password,Input.Pin,Input.Date,Input.Slider,Input.Frame,Input.Checkbox,Input.Switch),Layout(Layout.Flex,Layout.Grid,Layout.Container,Layout.Block,Layout.Separator),Status(Status.Empty,Status.Skeleton,Status.Deferred,Status.Error,Status.Progress,Status.Steps),Typography(Typography.Text,Typography.Link,Typography.Timestamp,Typography.Crawl) andMedia(Media.Image,Media.Player).ThemeProvideris nowTheme.Provider. General hooks live in@dxos/react-ui/Hooks(Hooks.useTranslation) and composition helpers in@dxos/react-ui/Util. The root exports namespaces only, soimport { Dialog } from '@dxos/react-ui'still works, but flat names such asButtonPropsanduseTranslationare gone, and so are the@dxos/ui-typesre-exports (import those from@dxos/ui-types).
AttentionGlyph moves from @dxos/react-ui to @dxos/react-ui-attention. (321c99f)
-
A submitted chat prompt shows in the thread at once, before it is persisted, and carries messenger-style delivery ticks (sent, delivered, read) until the agent takes it up; a prompt that fails to send is marked so in place and can be removed. Queued prompts now render in the thread itself, so
Chat.QueueandChatQueueListare removed.AiChatProcessorgainssend,removePrompt, anoutboxatom and athreadatom that projects the feed, the streaming turn and the outbox into one list of rows;AiChatProcessorStateexposesthreadin place ofmessages. (cef0fed) -
Add a lattice projection (
createLatticeProjection): shapes snap to a grid of fixed cells separated by gutters (256x128 cells, 128x64 gutters by default), span any whole number of cells, resize one cell at a time with the opposite face fixed, and preview a move, copy, resize or create onto occupied cells in red before refusing it. Smart links on a lattice route at right angles through the gutters, run straight through free cells, and are nudged into separate lanes where they share a gutter. Route corners share one radius; a link tool click without a drag draws nothing and returns to the select tool; hover clears while dragging; and a link's start and end markers sit side by side in the properties panel. Node types can be declared on prototypes (createNodeRegistry(types, prototypes)withextends); rectangle and scene share theboxprototype, and a scene shape now has a centred editable label, acontentsoption (shown by default while it has no label) and a zoom-in control.nodeDefmoved to its own module so views no longer import the registry. A guides toggle (toolbar,;) shows or hides the page frame and the lattice cells.SceneBuilderis now declarative:SceneBuilder.scene(id, [...])over element factories (node,rect,ellipse,class,note,link) refined with.properties(), nested scenes placed with.at(), andbuild()returning{ root, scenes }checked against the registry's schemas; the chainedcreate().rect()…form is removed. Node styles gain atone, 0 to 3 (outline, light, medium, strong; unset is 2), and the properties panel picks hue and tone together from a style grid of swatches (neutral and eight hues by four tones) instead of a hue select. A scene shape drops its fill as soon as it is zoomed into. On a lattice scene a lattice toggle (Shift+G) chooses whether snap lands on the lattice or the basic grid; with snap off placement is free. (597cdb7) -
Add numeric
min,maxandsteptoFormFieldOverride, so a form can offer a narrower range than its schema enforces. Canvas nodes gain a ports-per-side property; new rectangles, ellipses and classes share one 256x256 default size (nested scenes 512x256) in scene units, no longer scaled by the zoom; a palette drag centres the shape on the pointer and previews it in place of the browser's drag image; ⌘-drag copies the selection; a new link is selected; a link dropped on empty canvas creates a copy of its source shape; a selected node hides its ports; font sizes and port counts outside the editor's range no longer drop a stored node from its scene; and the multi-select panel no longer shares fields whose constraints differ. (44b7b80) -
Add
fieldOverridestoForm.Rootfor per-field label, description, placeholder, readonly, hidden and indeterminate (multi-object "Mixed") values, afixedgrid in form layouts, and an indeterminateSwitch; Enter in a text field commits it as leaving it does. The canvas properties panel floats over the scene, edits several selected elements at once, and uses the standard number fields for geometry and font size; canvas shortcuts fire only while the canvas has focus. (ec9f207) -
The pull request type opens as a triage list of every pull request in the space, showing each one's repository, title, CI checks, tracking tasks and state, ordered by relevance or time; its filter, sort and grouping persist per device.
@dxos/react-ui-menugains genericSortMenu/GroupMenu,@dxos/react-ui-querygainsusePersistentQuery, andPullRequestnow records GitHub'screatedAt/updatedAt. (64f1a7a) -
A pull request now stays on the task it is attached to, so a sub-task fixed on its own can carry its own PR alongside its parent's; only a second, different open PR on the same task is refused.
Task.artifactTargetis replaced byTask.checkArtifact, which validates without redirecting. (fcbb5c4) -
Cut the wait between submitting a chat prompt and the model request by 22–39% and between agent turns by 40–48%, and add
markWork,dxos:-prefixed User Timing marks that a perf harness joins across realms over CDP and DevTools shows on its Timings track, withai.request/ai.responsemarked around every@dxos/aimodel call. (cb1e218) -
Add
countWork, always-on work counters published on__dxosWorkCounters, and count automerge storage, ECHO query and SQLite statement work with it, plus per-method served calls inRpcTiming's readout, so a perf harness can budget on counts rather than timings. (1894fc1)
Patch Changes
-
@dxos/plugin-code/AcpAgentand@dxos/plugin-code/ComposerMcpexport the ACP turn engine and Composer's MCP surface, so a host other than the desktop app can run Claude Code with Composer's tools. Operations run underAssistantTestLayercan now useHypergraph.Service, as they can in the app. (94b63cd) -
The chat-completions adapter now fails
generateTextwhen the provider rejects the request. Before, the error body was read as an empty reply and the turn ended with no output. The provider's message is kept on the error. A tool call Ollama cannot parse (gpt-oss writes its arguments as a JavaScript object literal) is reported asInvalidOutputError, so callers can treat it as the model's mistake and retry. (c6922ce) -
ObjectCard.Headeraccepts an object snapshot as itssubject, so a card subscribed throughuseObjectshows its type's icon and hue instead of the dashed-circle fallback. (38e2ddb) -
Opening a space's settings closes the companion, as opening the app settings already does. Both use a new
LayoutOperation.closeCompanion(), which treats a layout without companions as nothing to close. (6ea9d4d) -
Opening a space now brings this identity's member profile in the space up to date with the identity's own profile. A display name set before joining, or changed while a space was not open, never reached that space, so other members (and the comment thread) showed a generated name such as "cool snake" until the name was edited again. (87785d9)
-
RemoteProcessHandleretries a failed event read with backoff instead of ending the subscription, so one dropped request no longer stops a remote process's outputs from reaching its subscribers.@dxos/react-ui-formnumber fields take their stepper increment from a newStepAnnotation, defaulting to 1 for integers and otherwise 0.1 or 0.01 by the size of the value. (0ee5ecf) -
Picking an EDGE in the devtools EDGE selector now sets the hub config entry (
runtime.services.hub.url,<edge>/hub/) along with the EDGE entry, so the two always name the same environment. Build-timeruntime.app.envvalues are left as built. (5e1f127) -
Reopening a profile no longer rewrites unchanged state to SQLite: hypercore feed files skip writes that leave their bytes as they are, the metadata record is saved only when something other than its timestamp changed, and a space restored with its saved root no longer re-saves its row. (162fd6d)
-
- Breadcrumbs: separators take the links' muted colour rather than a fainter, half-transparent one, so the trail's structure reads at a glance. A plank header's trail is built from
Breadcrumb.LinkandBreadcrumb.Current, so a crumb keeps its size and place as you move down the hierarchy.
- Breadcrumbs: separators take the links' muted colour rather than a fainter, half-transparent one, so the trail's structure reads at a glance. A plank header's trail is built from
- Unanchored comments: every comments companion's toolbar has a + button that adds a comment on the whole object, not anchored to a span. For an object with no text to select (a drawing), the empty state points to it.
- Chat widgets: a system-generated turn (the lightning row) collapses to its first line behind a disclosure caret at its end, built from the same panel as the tool, summary and fallback widgets. Suggestion and select buttons share one button.
-
Background tool results: a result recovered on a later turn renders in the tool panel as "Background result" (or a failed one), not as a raw
<result>prompt. (aad3e41) -
Card.Texttakeslines, and clamped text wraps inside a card row, which otherwise keeps its content to one line. A row of clamped text tops its icon against the first line. A GitHub card's description now shows up to three lines rather than one clipped line. (bb2b672) -
Cut the SQLite writes an agent turn causes by about a third: an indexing pass writes each batch to its snapshot and reverse-reference indexes in one transaction instead of two, and trace messages reach their feed in batches rather than one transaction per message. (1ef899b)
-
The contact list lays each contact out from the list item's own parts. The avatar sits in the icon rail, the name beside it with the shared spaces under it, and the identity and its copy button at the row's end. Before, the avatar floated mid-row and the text was pushed to the right. A list item whose icon cell holds an avatar now keeps a gap between the avatar and its text, as an icon has. (469e7f7)
-
The Create Space dialog puts the icon and colour pickers side by side, and its Cancel and Create buttons end at the fields' edge rather than in the gutter. Across forms, a control narrower than its field (a picker button) now starts under its label instead of centring. (665261a)
-
The
syncPeerspan with EDGE now times a space's whole catch-up: it spans reconnects, endssyncedorclosed(neverdisconnected), and records how many connections diverged and dropped (connections,disconnects) during the catch-up. (2e96a73) -
Layout and contrast fixes for the new
@dxos/react-uicomponents: -
Forms in a dialog or popover now line up with the host's columns, and a form in a popover takes the popover's surface.
- Combobox and select triggers placed directly in a form span the form's content column.
- A panel no longer shifts its body under the header when focus scrolls it.
- List rows with a description keep their icon and actions on the title's line.
- A scrolling block in a settings row (such as the debug port log) spans the row instead of collapsing to zero width.
- The log list scrolls inside its panel, an expanded entry opens beneath its row, a clicked row is ringed as current, rows' checkboxes are optional (
Logger.List checkable), and the drawer's focus ring is no longer hidden by its panes. - Row hover and selection are lower-contrast, and a fieldset's collapse button is a ghost button.
- The
descriptionof Project, Task, TaskSet, Milestone, Organization, Issue, PullRequest, Event, Pipeline, Skill, Routine and Script isFormat.Text, so forms edit it as multi-line text;Format.Textis also on theFormatnamespace from@dxos/echo/Format. - The task set's add-task editor stays at the bottom, below the list.
- Popovers are unpadded by default (the call site sets the inset; Body and Header keep theirs); a popup's arrow no longer covers its first highlighted row; menu checkbox and radio rows show the action's icon with a trailing check; an inheriting Container whose parent is no grid lays out its own column.
-
Select.Trigger'sfit='options'is now the booleanfixed(the trigger keeps its widest option's width); a selected tab takes the control fill. (945092e) -
- Settings lists scroll: the Devices, Invitations and Recovery lists in user settings no longer swallow the mouse wheel; the form scrolls over them.
-
Prompt bubble width: a chat prompt's bubble is sized by its own text, so it no longer resizes when the relative timestamp below it changes. (c531b05)
-
Indexing passes no longer read feeds that have nothing new: a caught-up feed is answered from memory instead of SQLite, and the two index legs of a pass share one read. Background passes started by trace-feed appends are coalesced to at most one per second, so an agent turn's trace writes no longer keep the database worker busy.
flushand feed-scoped queries still see trace messages immediately. (c7cc480) -
Layout fixes for board columns and dialog actions.
-
Board columns: every column has the same underlined header, the uncategorized one included.
Board.Column.Headertakes an optional drag handle and keeps its space when there is none. A column's cards scroll in a gutter, so they clear the column's edges. -
Dialog actions: the object-create, import-pull-request and custom-token dialogs put their actions in
Dialog.Footer, as every other dialog does, rather than in the scrolling body. An emptyDialog.Footernow collapses. (161f994) -
A popup's arrow opens the focus ring under its base, so the ring outlines a focused menu and its arrow as one shape rather than closing the arrow off. (8ebe8d6)
-
A ScrollArea contains overscroll only along the axis it scrolls, so a vertical two-finger swipe over a horizontally scrolling area (such as the project timeline's chart) scrolls the panel around it instead of being swallowed. (6a7bed4)
-
- Shortcut caps: the shortcuts panel draws modifier keys (⌘ ⌃ ⌥ ⇧ ⏎ ⌫ ⇥) as icons, so every cap's glyph is the same size, and shows letters in lower case. A
controlbinding now renders as ⌃ rather than the word. (c2a300a)
- Shortcut caps: the shortcuts panel draws modifier keys (⌘ ⌃ ⌥ ⇧ ⏎ ⌫ ⇥) as icons, so every cap's glyph is the same size, and shows letters in lower case. A
-
Mark the SDK, UI and plugin packages
"sideEffects": false(or a precise list where a module registers a stylesheet, custom element, devtools formatter or diagnostic), so bundlers drop modules that are re-exported through a barrel but never used. (17008f0) -
Card layout cleanups. A grid
Card.Roottakesgutter(rail,mdorlg) to widen its rails; stats cards uselg, so their rows sit further in at the same text size.Card.Rowtakesend, content centred in the end rail (unliketrailing, which reaches back into the content track); stats rows put their controls there, centred, and their units at its start, so values end on one edge. Every stats card header has one layout: the icon in the start rail, the title and optional info as a two-column grid, and the button or menu centred in an end rail that is kept even when empty, so the info ends at the same edge on every card. An icon-only button inside aBlockno longer adds its own inset, which had pushed it off-centre in the cell. The Surfaces card shows a selected role's surfaces as JSON blocks again (a label row had clipped them to nothing), and the EDGE, Indexer and Sync cards show each space's name or id beside its copy button rather than a bare icon.Card.Rowtakesspan—fullacross both rails,endon through the end rail — in place of hand-written grid-column overrides, and a markdown card's word count now spans the rails as its snippet does, so the two start at the same edge. A parent task's timeline lane carries every descendant's start and finish as nodes, read from the task tree, so its first node is where its sub-tasks' work began even when they are not on one checklist. The project timeline's horizontal scrollbar spans only the chart, not the sticky lane names, via a newtrackStartonScrollArea.Root. The debug port's session id is a disabled copyable input, as the Space ID is. A form's markdown field (e.g. a task's description) fills its frame and wraps long tokens such as an inline-code URL, so it no longer scrolls sideways with its scrollbar mid-field. (4f8e566) -
A failed document-update batch, such as one that times out while the worker is busy, no longer stops the space's database for the rest of the session. Before, every new object in that space was refused with
RepoClosedErroruntil the page reloaded. The batch is now logged and retried with backoff. (a999417) -
Speed up local writes on OPFS: SQLite temp files now stay in memory, and Automerge chunk writes that arrive together commit in one transaction instead of one each, so a large flush no longer times out its RPC. (8d0cdd5)
-
Migration modules import
SqlMigrationsfrom the@dxos/sql-sqlite/SqlMigrationssubpath instead of the package barrel, so bundling@dxos/clientno longer pulls wa-sqlite and the OPFS worker into the app's static import graph (about 100 KB off Composer's eager boot graph). (e65ca2f) -
AlertDialogcloses only through its own controls, andAlertDialog.Rootno longer takescloseOnInteractOutsideorcloseOnEscape. (d2a6aad) -
- Inbox conversation: each message tile is a grid card, so the sender's avatar and the detail rows' icons (recipients, attachments, tags) share one start rail and every text starts at the same edge; the disclosure caret sits after the sender's name and the open/close animates.
- Card.Section: merges a
classNamefrom anasChildparent, soCollapsible.Content asChildkeeps its height animation; a collapsible on a section keeps the section's subgrid. -
Card.Row:
align='start'centres the leading icon and trailing cell on the row's first line, for a title over a snippet. (7d222fc) -
The
Loadingtesting component no longer crashes under a production React build, wherecaptureOwnerStackis not exported. (1b37aa8) -
Long lists of rows with differing heights can now be windowed:
useVirtualRows,ListboxandTreeacceptvirtual='measured', which mounts only the rows in view and measures each as it mounts. The task list uses it, so a project with hundreds of tasks no longer renders every row, and checking a task re-renders only the rows in view.
Obj.getSnapshot no longer throws and catches two errors for every non-relation object it snapshots. (49731e1)
-
Streaming an assistant turn no longer re-renders the whole chat. Folded tool runs keep their identity between updates, message toolbars re-render only when their own message changes, and the chat's toolbar, composer and checklist no longer re-render on every streamed block. (cbba318)
-
ContentBlock.ToolCallgains presentationaldisplayNameanddisplayIconfields, which the assistant's tool row prefers over the operation name and icon. Code mode sets them on eachevalcall from the operations its code invokes, so the call shows as e.g. "Create task" instead ofeval. (dc16fdd) -
Scrolling a long message feed no longer janks. Rows no longer re-render on every scroll event, a jump fills in a few rows per frame (visible rows first) instead of mounting the whole window in one task, and CodeMirror's shared stylesheet is no longer rewritten each time a row mounts (
style-mod4.1.4).TogglePanel.RoottakeslazyMountto build its body on first open. (4b50966) -
Form.Contentnow submits on Ctrl+Enter as well as Cmd+Enter, including from a markdown field, and only when the form is valid, so the create-task dialog creates a task from the keyboard and does nothing while the title is blank. The dialog's description is now a multi-line markdown field. (eb14798) -
A deferred
ActionMenu(deferUntilOpen) no longer builds its action graph until it is first opened, so a list that renders one per row mounts each row without creating a graph per menu. (ecd099a) -
Scrolling a markdown document does less work per frame: images are decorated as the parser reaches them instead of by re-scanning the whole document on every scroll, and the remembered scroll position is measured once per frame in the editor's own measure phase instead of forcing a layout on every scroll event. (ab1bddf)
-
Pressing Enter on an empty second bullet in the markdown editor now ends the list. It used to insert a blank line that made the list loose, after which every Enter in that list added another blank line. (7a177b9)
-
- Remote cursor name: a collaborator's name shows as a tooltip on hovering their caret, drawn outside the editor's scroller so it is never clipped; it sits above the caret like a flag, stays up for at least a second, hides when the peer moves, and hides the caret's dot while shown. The caret keeps the name as visually hidden text for assistive tech.
- Banner: a neutral (default) banner is transparent and bordered, with the host's text colour and a muted body; valence banners keep their own surfaces. The chat's plugin prompt is now a Banner.
- Devices settings: the logout section is headed "Danger Zone", with the full warning on the Log out field. (3d05b7f)