gen.image{prompt} is a service inside the assistant: on a worker it
runs the creator pipeline for the image domain against the node the
runner picks (LAN discovery, ETA-ranked, the resident flux model wins),
streams the node's progress into the tool card, and writes the picture
under the makepad home's gen/ dir; the creator library gains
generate_bytes — the request, poll and fetch that generate_and_publish
now shares — so no second pipeline exists. photos.add{path} bakes that
one file into the open library (only from the gen dir or the person's
home), re-opens the wall and glides onto the new picture; the module
executor answers it later through the host's reply sink. The model
chains them, launching photos in between. A registry seam found on the
way: a call dispatched in the same event a link was adopted reached the
port before its Registered, so the registry now answers a leading
Register at once.
The wall gained a search box: every keystroke re-cuts the packing over
the matches (every word in a title or link; title beats link, a whole
word beats a substring), each picture flies from its drawn rect to its
target over 450 ms, dropped pictures shrink and fade, returning ones
grow back; Esc clears; ⌘F or a bare slash focuses the box; the status
reads "35 of 293 · ro". photos.filter{query} sets the same from the
pane; instances are rebuilt only while a flight runs, and the clock is
the platform's.
Proven on the fleet: "make me a picture of a red bicycle on the moon
and put it in photos" → the file in 40 s, photos launched, added and
shown among the comics; typing r, ro, rob re-packs the wall live; the
filter through the pane in a process tile and as a module. ai-services
39, aichat 5, photos 9, image_tiles 12, creator 9; aichat and photos
check for wasm32.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A service over the engine the UI already drives: status (what is live
and next, the fader, overlay, autopilot, bpm), search over the catalog,
cue (the UI's content-click path), fader, next, autopilot with a style,
overlay, and the decks — deck_play, deck_stop, deck_load, crossfade —
through the same functions the console's controls call. A context line
follows the live item, fader and autopilot. Written by the delegate from
the sheets/files shapes; vj's ai tests 4, the binary suite 821 (the two
media decode-pool timing tests fail on this Mac before and after).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Five 16 px icons in the set's own style (our SVGs, stroke 1.2,
currentColor), wired into the shell's icon set and the launcher map.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The same tools route's own assistant has — plan, add and remove stops,
status, along-the-way search, map fly-to and trip framing, layers,
theme, markers, geocoding, weather, trip history, navigation — go on
the AI bus from one table (the definitions local_agent already maps),
dispatched through the one execute_tool; reads are Read, anything that
moves the map or changes the trip is Act. The context line carries the
map view and the trip; the desktop pane opening closes route's own
assistant panel. Written by the delegate from the sheets shape; route
25 tests.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Dormant instances registered their services, so the assistant could
type into a shell or steer a page nobody could see. The port opens at
startup for a real launch and on WmEvent::Adopted for a standby, the
way files already did.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
An ok os.launch result is held while the launched app is not on the
bus and delivered when it registers (within 8 s), rewritten as "<App>
is running now. Its tools: … Call them directly." with the tool table
rebound mid-turn where the model can (the local model prepends the
update to the tool result; Claude keeps its native table until the next
turn and gets the names in the text); past the patience the result says
the app has not connected yet. An assistant entry that never got
visible text is dropped before a tool call and at the end of a turn,
and the panel draws an empty one as nothing — the blank block above
the first card is gone. The model's context now opens with the running
apps and their tool names and lists the others as os.launch candidates;
the WM's launch description says a running app's tools are already
there, and its answer for one that is already running says so and
brings it to the front.
Proven on the fleet model: "open the photos app and find the pictures
about dogs" → launch (running 4 s later) → search, summary, search →
the answer, one turn, the tile beside the pane. ai-services 38, wm 153,
aichat 2; aichat checks for wasm32.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The placeholder used the focused-text colour, and the composer is
always focused, so the hint looked like an entry.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
apps/photos (lib + bin) puts libs/image_tiles' TileGrid in a tile: it
opens a baked library found by name (IMAGE_TILES_HOME, the cwd's
local/image-tiles, the checkout the binary was built in — the smbc
collection first), shows a status line with the bake command when
there is none, and exposes photos.search (every query word in a title
or link), photos.show (the camera glides onto one picture) and
photos.summary — the same answer for the port and for the module's
executor. PhotosModule mints the view inside an isolate with an open
schema that takes a collection name, never a path; the WM links it
behind app-photos and lists it in the menu. image_tiles learned to
decode GIF and WebP and to read a manifest's pictures from disk, so
the bake can take local/smbc's mirror: the last 300 comics are baked
under local/image-tiles/smbc (293; seven of the mirror's files are
saved error pages). fabric joins the launcher with a title and a
polite close.
Driven hidden: the wall in a process tile beside the left pane, panned
and zoomed; search and show cards; the same wall as an in-process
module; fabric launched and closed; standalone photos with the F10
overlay on the left. photos 7, image_tiles 5, wm 152; the photos lib
checks for wasm32.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
sheets: read_range (one cell or an A1 rectangle, up to 2000 cells, rows
as tab-separated display values), find (case-insensitive over the used
range, 50 hits), write_cell and set_range (Act) — edits go through the
same commit path as paste and direct entry, so recalculation, undo and
the chrome all see them; the module executor answers the same tools.
files: mkdir, rename (a bare name, no separators) and trash (into the
app's own trash dir, never a delete) — Destructive, so the router shows
a confirm card first; every path through the jail, on the demo VFS as
on disk. Written by the delegate from the existing shapes; sheets 88,
files 158 tests.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Two services on the AI bus. terminal: read_screen (the visible grid as
text, cursor and cwd in the note), read_scrollback (up to 2000 recent
lines) and run — which types the line into the live, unsandboxed shell
exactly as the person would, refuses control characters and anything
over 4 kB, and answers at once so the model reads the outcome with
read_screen next. browser: page (the active tab's title and url — CEF
exposes no page text, so none is promised), tabs, navigate and new_tab,
http(s) or about:blank only. Context lines: the shell's cwd, the active
tab. Written by the delegate from the sheets/files shapes; terminal
331 + 5 tests, browser checks.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Decision 17: the chat never sits over the app. Under the WM the pane is
a left column of the desk row — its walk width is the reserved strip,
eased from nothing to the card plus a gap as it slides, the card
right-aligned in the strip so it comes in from off the desk's left edge,
its edge on the right — and the desk's layout takes what is left, tiles
snapping to it while the strip moves the way they follow a drag. In a
standalone Window the F10 slot does the same: it reserves the strip as
the body's left inset every frame, lays the body out beside it, and
reads the app's own ground colour after its retint. The background
switcher's index lives on App, not in a static.
Verified by hidden grabs: a terminal full width; F10 → the pane on the
left and the desk narrowed by 450 px with the terminal filling it; F10
→ full width again. sheets standalone: F10 → the grid starts right of
the card, nothing over cells; F10 → back. wm 152, widgets 138 (+ the
two known widget_tree failures), sheets 84; the WM checks for wasm32.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Driven native, one app at a time, with the assistant up at boot:
terminal, files, task and browser warm-adopted; sheets, image, video
and pdf launched cold; sheets also as an in-process module; the tools
answering through the pane (os.list/launch/close/open, files' listing,
a refused jail escape, a treemap, sheets' summary both ways).
What broke and is fixed: when a window closed or a client died the
layout's automatic refocus took the keyboard from the OPEN chat, so an
os.close typed in the pane sent the next console line into a sheet —
the refocus now leaves the keys with the pane while it is open (a click
on a tile still moves focus, through focus_client). A warm spawn that
cannot start (an installed layout without the binary) counts as a crash
so the pool gives that app up instead of retrying every tick. browser
and sheets link the WM API: a title in the bar and a polite close on
CloseRequested; aichat quits on CloseRequested (the desktop going down).
Measured (WM log, launched → first flip): warm-pooled apps 25–50 ms;
cold launches through cargo's freshness check 0.7–3.7 s (up to 14 s
under a parallel launch's target lock); the same binaries run plain
0.3–1.5 s after macOS has scanned them. wm 148, sheets 84, aichat 2.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
basecamp/omarchy answers 301 on the API and the importer fetched no
wallpapers; the repo is omacom/omarchy now, same quattro branch.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The desk (layout, tiles, the shell, the AI pane, the module host, the
bus) is one program everywhere; what differs around it is asked through
host.rs: a monotonic clock in platform seconds (std::time traps on
wasm), whether child processes exist at all, a child's environment, the
theme choice kept in the desk's own storage namespace. Every Instant in
the WM is gone; the hub, the warm pool and process launches are skipped
where there are no processes, and the bar's clock falls back to the
platform epoch when it cannot fork date.
The pane has a second body: where the chat is linked in as a module —
the web build, or a desktop that switched aichat to module hosting — the
pane instantiates mod.widgets.AiChatOverlay by name, exactly as a
Window's F10 slot does, and the WM's own os service and every module
instance reach it as in-process links (pane_links.rs), never as frames.
The registry's web profile makes every linked module a Module and
answers os.launch of anything else with unavailable. sheets' Open and
Save go to the instance's storage jail, asynchronously, on every
platform.
The assistant starts with the desktop (decision 15): the aichat child
(native) or the overlay (in-process) comes up at startup with the pane
closed and no focus taken, drawn just off the desk's edge so the child
is configured and presents before any F10 — which now only slides it
in. The gallery fixture leaves the desk's DSL for a by-name host (its
construction overflowed the wasm stack).
Platform bug found by the web drive and fixed in libs/wasm_bridge: the
ToWasm reader added a block's absolute end to a relative base, so two
JS→wasm messages in one buffer decoded garbage and trapped; it seeks to
the stored end, with a batched-buffer test.
Verified natively by a hidden drive: the child's first frame 1002 ms
after boot, before any F10; F10 → the pane at once with the composer
focused; F10 → gone. On the web (threaded build, 1.5 MB brotli, COOP/
COEP): desk, pane with No model, os.list, an in-process Sheets tile and
its summary, terminal answered unavailable, zero traps. wm 148, sheets
84, app-module 3, wasm-bridge 1; wasm32 checks and the std::time clippy
gate clean for wm, sheets, app-module, aichat, wasm-bridge.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
libs/app_module (makepad-app-module) is the contract (aicontrol §3):
AppModule (id, label, register into an isolate, an OpenSchema, create
into InstanceParts, capabilities), InstanceHandles (an InstanceScope
owner token, the storage jail as a cx.storage namespace, the viewport,
a ReplySink for calls that finish later), a ServiceExecutor addressed
apart from the root, and an OpenSchema that refuses raw paths — a file
is a handle the host issued or nothing. Only types live there.
The WM hosts one (module_host.rs): allocate the isolate, retint its
theme from the palette, register, create — one trusted entry into the
isolate, never a second &mut Cx beside the VM; teardown drops the root
first, runs shutdown in the isolate, frees it. MpModuleView is the tile
for an instance's root, drawing and dispatching with the isolate
INSTALLED on Cx (enter_isolate/leave_isolate, new in widgets) and
gating keys on the WM's focus; a TileHost trait covers both tile kinds
so the desk and the focus logic never ask which. The registry overlay
(apps.rs) links modules per app-* feature; the desktop default stays
Process, switched per app in ~/.makepad/wm/apps.splash or by a dev
--module flag. The bus gains its in-process leg: an instance is an
m<id> endpoint the pane addresses like any other — the leg the web
superbuild runs everything on.
sheets is lib + bin: SheetsModule mints MpSheets{} in the isolate and
answers sheets.summary on its executor; the standalone binary keeps its
Window and F10 overlay behind the standalone feature.
The drive found a platform bug: a shader compiled on a widget minted in
an isolate hit the draw-shader object cache by object index alone, so
an isolate's Button reused the main heap's entry and drew with zero
instance slots. The cache is keyed by (heap, object) in every backend,
and add_instance refuses a zero-slot draw call instead of dividing by
it. Isolate cost, measured (the P2 entry gate): 12 ms and ~8 MB per
isolate, flat to 32 — no pre-warming needed.
Verified by hidden grabs under the WM: /os.launch sheets → an
in-process Sheets tile (no child process), the apps row Desktop ·
Sheets, /sheets.summary answered through the in-process leg, a warm
terminal beside it, F10, close → the instance torn down and its isolate
freed. wm 145, sheets 84, app-module 3, services 33; platform and draw
check for windows-msvc, linux-gnu and wasm32.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Every Window now carries an AiChatSlot beside the tweaker: zero cost
while off, inert when the window manager hosts the process (the WM's
pane is the chat then), and on the first bare F10 it instantiates the
chat's module root BY NAME — mod.widgets.AiChatOverlay — which exists
when the app links makepad-aichat and calls its script_mod; an app that
does not gets one log line. The overlay slides in from the right over
the body with the WM pane's motion, owns the pointer inside its rect and
the keyboard through its composer, keeps ticking while hidden, and draws
in the window's retained overlay list so it composites over the deferred
body. Requests from outside the tree ride Cx globals, never statics.
An app exposes itself with one call: AiServicePort::open(cx, manifest)
is the hosted transport under the WM and, standalone, an in-process link
parked on Cx (PendingServiceLinks) that whichever chat root is up adopts
into its registry — the overlay today, the superbuild's pane later. The
registry wakes the UI when it sends, so an in-process call is answered
without waiting for a pointer event. NoModel leaves the engine feature
so a build without a model runtime still answers honestly and keeps the
tool console; aichat's engine is a default-on feature.
The bridge: Cx::ai_callback beside tweak_callback, /ai?on=1|0, /ai?say=…
and /ai/transcript (the overlay publishes the transcript as JSON after
each state change), installed by makepad_aichat::script_mod.
sheets links aichat and exposes sheets.summary (name, used range, header
row, selection) through the port: standalone the overlay answers it,
under the WM the bus does.
The local model no longer loads on a registration: its session starts
on the first user line, so an app joining the bus costs nothing.
Verified by hidden grabs: sheets standalone /ai?on=1 → the overlay with
the summary card and no model; F10 closes it; under the WM the sheets
tile shows no overlay and F10 toggles the WM pane. widgets 135 + 4
(two widget_tree find_within tests fail before and after this change),
aichat 33, sheets 83 + 2, services 29; widgets and aichat check for
wasm32.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Hosted by the window manager, files opens one AiServicePort with a
manifest built from the same table the app's own panel reads its tool
specs from, so the two can never drift: list_dir, read_file, stat,
treemap_summary, all Read. The calls run on a worker of their own
(ai_service.rs): every job carries the engine's call id and a cancel
flag the folder walk checks on every entry, a queued job cancelled
before its turn never runs, treemap_summary reports a permille per
direct child, and results come back by id whatever the order. The old
panel's order-only runner stays beside it for the old chat, behind the
chat feature it belongs to.
The port opens at startup unless the process is a warm-pool standby,
which waits for Adopted so a dormant instance never shows as a running
Files; a context line (folder, view, selection) follows every change;
ChatOpen from the desktop closes the app's own panel; the jail resolves
every path exactly as before.
Verified by hidden grabs under the WM: /os.launch files → the pane's
apps row reads Desktop · Files; list_dir, a refused jail escape, and a
treemap summary answered as cards. 151 tests.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>