Skip to content

Fix/weather recursion - #316

Closed
aethctl wants to merge 243 commits into
Ryoku-dev:mainfrom
aethctl:fix/weather-recursion
Closed

aethctl wants to merge 243 commits into
Ryoku-dev:mainfrom
aethctl:fix/weather-recursion

Conversation

@aethctl

@aethctl aethctl commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

What this fixes

The Python bar weather scripts can enter a recursive process spawn loop when weather data is requested before a location has been resolved

Fix

weather.sh now sets RYOKU_WEATHER_RESOLVING=1 when it invokes location.sh to resolve a missing location.

location.sh checks the flag before triggering its automatic weather refresh
This keeps the existing behaviour for standalone/manual location refreshes while preventing weather-driven location resolution from recursively launching another weather process.

neur0map and others added 30 commits September 26, 2026 23:47
The ryovm, ryoport and security-key launches built `--class NAME`, which is
kitty's form. Ghostty's CLI wants `--class=NAME`, so it read the bare flag as
valueless and then parsed the name as a second config field: every connect
opened Ghostty's configuration-error window with `class: value required` and
`ryoport-ssh: invalid field`, and the class never applied. The `=` form is
accepted by kitty, foot, alacritty and ghostty alike.

The names moved to reverse-DNS ids (dev.ryoku.ryoport_ssh and friends) because
Ghostty validates `class` as a GTK application id, which requires a dot: in the
right flag form the old bare names were still rejected and ignored, the window
kept com.mitchellh.ghostty, and the float-and-centre window rule could not
match it. The ryoport rule matches the new id, and ryossh's terminal switch
gained the missing Ghostty branch instead of falling through to a bare -e with
no class at all (issue Ryoku-dev#280).

Note: Fixed: ryovm and ryoport open cleanly when Ghostty is the terminal, and their windows float and centre as intended
ryossh ships as a packaged binary and now carries the terminal-launch switch
that issue Ryoku-dev#280 was filed against, but no workflow built or tested
ryoku/apps/ryovm/remote, so its tests only ever ran on a developer's machine.
It joins the other modules behind a path filter and a build/vet/test job, the
same hole that let an ipc compile break reach unstable-dev unseen.
Services, systemd timers (active and dormant), the cron family, docker
containers, listening sockets, top processes, and block mounts, gathered
concurrently with per-section staleness stamps. Deterministic tips turn
observations into the command you would run; rashin never runs it.
The scan walks each detected coding agent's own layout: skills (following
the symlinks wire lays), memory files and databases, session counts, the
active model, and where credentials live by name only, never values.
/api/harnesses reports it per agent. prowl api answers code-intelligence
queries over loopback; rashin starts it on demand and proxies it as
/api/code/* plus /api/providers, keeping one origin for the dashboard.
A box without Prowl says so instead of showing an empty panel.
Nine panels: SYSTEM shows services, timers, cron, containers, sockets,
processes, and mounts read-only, with tips whose commands stay yours to
run; the harness ledger and per-harness skill strip come from the new
scan; MODELS lists the free/credits/paid directory and marks keys that
exist on this box. The memory graph gains a 3D orbit renderer beside
the force layout, the hero carries a live compass needle, and a rail
switch turns all motion off at once. Cron directories of scripts are
listed as scripts instead of being parsed as crontabs. Three.js and
anime.js are vendored; the build still needs no node.
feature.md is the order for an ask the desktop does not cover: ryostore
catalog, then the machine's own catalogues, then build a plugin. The
vault's AGENTS.md and desktop.md now carry the same rule, so an agent
that only reads the vault still climbs it before writing code. The
dashboard docs describe the nine panels the site now has.
The poster look is gone: the 3D compass, the orbit graph, the motion
switch, and the vendored three.js/anime.js with it. What is left is a
neutral dark console with a nav rail, live status dots, and dense
tables. System is one tab per surface with a filter and grouped tips
instead of a clone per failed unit. Vault groups maps, memory, and
journal and collapses the source mirror, which was most of the list.
Skills tabs per harness so it is clear whose skills are whose. Code
intelligence leads with measured token savings, the number that
matters, not the file count. The credential scan now reports only
model keys, so the ledger and the on-box join stop showing session
tokens as provider access.
The console read as a generic dark SaaS: side rail, header, card grid,
one acid accent. It now wears the vernacular of its subject, a machine
drawing. A masthead of numbered sheets replaces the rail; the body is a
drafting sheet on a faint blueprint grid; a title block of machine facts
(host, kernel, uptime) runs along the foot. Prussian blue sheet, chalk
line-work, annotation red, semantic green/amber/blue for state, zero
radius, hard rules. IBM Plex Condensed carries the chrome and Plex Mono
every number; Archivo Black retires with the poster era. Overview leads
with an instrument band of segmented gauges with a redline mark instead
of KPI cards. The Hub's Rashin page mirrors base.css by contract, so its
palette and bundled fonts follow, and the favicon turns blueprint too.

Note: Fixed: the dashboard no longer looks like every other dark web app
The launcher's blurred frost is a still of the desktop, so it needs a
capture surface that lives as long as the launcher. niri recreates its
outputs under a surface like that, and the Qt client segfaults resolving
the vanished screen, which took quickshell down the moment the hero
launcher opened. The seam now carries persistentScreenCapture, claimed
only by Hyprland, and both launcher variants gate their frost on it; on
niri the card opens over a solid drawer through the path a failed
capture already used.

Note: Fixed: the app launcher no longer crashes the shell on niri; its blurred backdrop opens as a solid drawer there instead.
The spectrum grew a twelfth look that is not a box: twelve eased
sectors flow along whichever screen edges you light, a pair of rails,
a bottom horizon or a joined perimeter, as one organic current in four
materials, four movements and seven effects. The geometry and colour
live in Ryoku.Ui.AuraField with its own analytic pass (shaders/
aura.frag); lib/aura.js folds and follows the shared cava bands the way
place.js owns the box math, tested beside it. AuraMotion is the look's
Motion twin: idle/halve rules, adaptive tiers, and the field resting
instead of freezing on silence. Wallpaper-lit by triad, pinned by
three exact colours. The gallery, the desktop editing bar (EDGES,
MATERIAL, REACH) and the Hub's Visualizer tab (EDGE FIELD section,
preview through the same AuraField) all carry it, and box-only knobs
hide while it is chosen rather than sitting dead.

Note: New: the visualizer's aura look, a living current of light along
the screen's edges, edited from the desktop bar and the Hub
The MATERIAL group anchored its Btn vertically inside the Group's
Column, which Qt cannot lay out: the whole control row collapsed, so
the editing bar shipped with the aura look was dead for every knob,
not just the new ones. The Btn sits in the Column like its sibling
controls do.

Note: Fixed: the visualizer editing bar stopped working entirely while
the aura look was chosen
The EDGES chips fed their lit state to `armed`, which Btn treats as
enabled, so an edge that was off could never be turned on: with the
default left+right rails the top and bottom chips sat inert and the
look read as locked to the vertical edges. Lit edges now wear the
filled plate and every chip stays clickable. The same pass closed the
ways the look deviated from the rest of the catalogue: a single pinned
colour tints the field the way it tints every other look (it used to
demand a complete triad and silently ignore one), the placement guide,
the drag and the wheel stand down for it since it owns the whole
screen and never reads a box (they only rang the display with a dead
rotated rectangle the look ignored), the bar dims its inapplicable
knobs instead of hiding them so the row cannot reflow mid-aim, and the
hint line names only the keys that actually edit it.

Note: Fixed: the visualizer's edge-field top and bottom edges could not
be lit from the desktop editing bar
The blueprint skin was still a costume: its own palette, its own type,
nothing of the desktop in it. The dashboard now speaks the Hub's
language and wears the desktop's live palette. A new /api/theme resolves
the Material roles the way Tokens.qml does (named scheme, then the
wallpaper, then the signature default), so the page retints with the
wallpaper within seconds, light schemes included. Emphasis is a bone
plate, colour is data, the seal stays vermillion, and the type is
Fraunces, Space Grotesk, Space Mono and Noto Sans CJK JP as subset woff2.

Navigation is three floating islands like the default QS Bar. The
Overview opens on the wallpaper on screen (/api/wallpaper serves the
file ryogami reports; a live one plays muted while visible) with the
desktop clock and a sysmon readout over it. Every sheet gets a kanji
gloss, a Fraunces title and a one-line lead; the memory graph drops its
rainbow for tone and ring; status copy is written in plain sentences.
The Hub's Rashin page reads Tokens like every other page, so the brand
takeover and its bundled fonts are gone, along with unused poster art.

Note: New: the Rashin dashboard follows your wallpaper and theme, and opens on your wallpaper
When Rashin is on, anything the machine already knows is wrong can be
handed to the agent. Every tip on the System sheet, every finding on a
new Doctor tab (ryoku doctor --json, read-only, cached), the Overview's
health band, the Hub's Updates page after an update whose health check
found issues, and ryoku doctor itself offer Fix with AI. The daemon
opens a fresh chat and briefs the agent with the problem and how to
work: gather evidence first, check ownership before editing, ask before
anything destructive, verify, say how to undo, note it in the journal.
From a terminal, rashin fix app <name> <what happened> does the same.
POST /api/fix refuses other sites.

Every agent wired through Rashin now knows how to work on this box.
ryoku owner <path> classifies any path (overlay, fork, generated, tool
store, seed, user override, shipped and overwritten on update, package)
and names where the change belongs; --map feeds a new vault ownership.md.
ryoku-rashin logs <app> gathers units, journal, coredumps, OOM kills,
the app's own log files and its recent package changes in one bounded
bundle, and logs.md maps every log source on the machine. AGENTS.md,
the ryoku skill (with a new troubleshoot.md playbook) and the Needle's
identity carry the rules: check ryoku owner before an edit, never touch
what an update overwrites, fetch the logs yourself when something breaks.

Note: New: Fix with AI on doctor findings, tips and after updates when Rashin is on
Note: New: ryoku owner tells you who owns a config file and where a change belongs
Note: New: rashin logs <app> gathers everything about an app that broke
Port the iRiS frame family from iNiR into the shell as a shipped bar style
and make it the default. iRiS is not a bar but a whole frame: an island on
any screen edge that morphs into whatever you clicked, with glass popups,
floating bubbles, a dock, a live Studio and its own settings overlay.

The family keeps its module tree under ryoku/shell/quickshell/inir and
reaches the desktop only through the window-manager seam and the daemon's
settings topic, so it runs unchanged on Hyprland and niri. Its store is
namespaced under the `inir` key of shell.json, so it never collides with
the keys the daemon validates. Wallpaper, notifications, tray, night light,
idle and the palette plane bridge to Ryoku's own services rather than
starting second ones. The barstyle Scene is a thin per-monitor host that
drives the reference's boot ladder.

Registered in BarProducts builtins, the ryostore catalogue and Hub Bar
Studio; docs/barstyles.md updated.

Note: New: iRiS is the default desktop bar, an animated island-and-frame
that morphs into popups, a dock, bubbles and its own settings and Studio.
The port pruned the reference's global-actions daemon but left the
search pipeline calling it, so every typed query died on a TypeError
and the palette showed nothing. A trimmed action registry now ships in
its place, wired only to the services the frame actually has, and the
emoji catalogue behind the ':' search mode was restored from the
reference with its vendored data. The qmldir files carried the same
pruning scar: singleton entries were listed two and three times, which
broke the whole frame's scene load; each is now registered once.

Note: Fixed: the iRiS spotlight can search apps, actions and emoji again
Settings -> App Launcher -> Spotlight makes Super+Space open the
frame's morphing-glass search: the variant drives the frame's own
searchOpen flag when the iRiS bar style hosts the palette, and mounts
the frame's palette surface itself under any other style, so one glass
serves both. The dock's nine-dot now opens whichever launcher style is
active through ShellState instead of the frame's spotlight directly,
so the shell and the frame agree on one palette.

Note: New: the iRiS Spotlight is a launcher style, and the dock's
nine-dot opens the active launcher
Pinning from the dock menu wrote through setNestedValue with an array
path, which stringified into one dead key, so the pin never reached
shell.json; the taskbar model also listened for per-key change signals
that a plain JSON mirror never emits. Array paths now join before they
become keys, and the model rebuilds on the mirror's own change signal.

Note: Fixed: pinning an app to the iRiS dock now saves the pin
neur0map and others added 27 commits October 1, 2026 13:39
The vendored recipe existed because scenefx was AUR-only; extra has
shipped the same 0.5 tag since, with the identical libscenefx-0.5.so
provide and scenefx-0.5.pc. Two copies of one library is the repo's
one thing rule, and the duplicate's conflicts line made the container
gate reject ryoku-desktop-mango beside the host's scenefx. The package
never reached a user: every publish since it landed failed. caps'
reclaim list, doctor's diagnostics, the variant depends and the ISO
comment now name scenefx; glslang leaves the build toolchain with the
recipe that needed it.

Note: Fixed: the desktop install gate rejecting the mango variant
Arch adopted mango into extra, and its 0.17.4-2 outranked our vendored
0.17.4-1, so the container gate resolved ryoku-desktop-mango's dep to
the official build. That build ships the greeter entry as Exec=mango:
a first login on it boots the bare compositor with no keybinds, no
autostart and no shell, and its mango.desktop collides with the
wrapper entry ryoku-desktop-mango owns. epoch=1 makes our build, which
leaves the session entry to the variant package, the install candidate
for good. Probed with makepkg: 1:0.17.4-1 builds and carries no
mango.desktop.

Note: Fixed: the desktop install gate resolving the mango variant to
the official mangowm build
actions/upload-artifact refuses ':' in member paths, and mangowm's
epoch puts one in its filename, so the build job's repo dir no longer
fits the transport. The artifact is internal to this workflow -- the
gate and the publish both consume it -- so it packs to a single tar
after the build and unpacks it in both jobs. The db and every .sig
ride unchanged; only the transport differs.
An unversioned dep is satisfied by repo order, and [ryoku] sits after
the official repos: the gate kept resolving plain "mangowm" to extra's
0.17.4-2 despite our 1:0.17.4-1, and extra's build owns the greeter
entry the variant must own. The dep now reads mangowm>=1:0.17.4, which
no epoch-less build can satisfy. Reproduced and verified against the
published db with pacman -Sp: the constraint resolves to our file://
package while the bare name resolves to extra.
Note: Fixed: desktop widgets now wear their edit frame (all built-ins,
Shima and Python faces), Reset restores every widget's state, plugin
rows show real on/off, and the widget catalog opens as categories with
a card grid instead of one long strip.

- WidgetPicker: a category rail (Ryoku / Shima / Python / each installed
  plugin set, with an on/total count) and a two-column grid of widget
  cards; search spans every category with a family eyebrow on each hit.
  Cards keep their identity across toggles (shape signature), arrows
  navigate the grid, Up returns to the search field.
- Desktop: the edit frames resolve the real WidgetSlot (the loaders
  box the whole screen) and cover dayprogress, shape and all 46 hosted
  faces; frame Settings opens at the hosted slot; widgetTitle names the
  hosted faces. The Reset snapshot is generated from the rosters so no
  widget is left out, and it carries the visualizer's flag.
- Desktop: a plugin's picker row reads the installed set (Registry now
  sweeps discover.sh --all) and its live placement, so a hidden tile is
  switchable again instead of stuck reading on.
- Desktop: the picker's tune routes to each scope's real editor: the
  inspector for slot-hosted widgets, the Placer for the visualizer, the
  tile menu for a plugin; the inspector never opens on a null slot.
- WeatherFaceRound honors the ryokuBare host hook, so Ryoku style stops
  double-drawing its pill plate.
- Copy: the Shima clock hint typo, Python hints, and the widget menu's
  raw scope titles (Day Progress, All-in-one).
The wizard gained three steps between the graphics mode and the disk.
Window manager installs the chosen compositor variant; Web browser
picks exactly one of Zen, Chromium and Firefox and points both xdg
and the desktop's browser role at it; Apps & tools is a grouped
keep/remove checklist over every optional app, with the rows that
back a desktop feature marked required and refused. The removals
reach the backend as RYOKU_DROP_PACKAGES, are filtered out of the
pacstrap and AUR transactions, and are seeded into the doctor's
provisioned ledger, so ryoku update treats them as removals instead
of reinstalling them on every lane.

Note: New: the installer asks which window manager, browser, and apps
to install, and the update lanes honour those choices
install -d chmods an existing directory, and ryoku-network-kill ran it
with -m 700 against /var/lib/ryoku: every Hub Connections toggle put
the tmpfiles-owned 0755 back to root-only. Sessions lost their boot-ok
writes through the sticky subdir, and ryoku update could no longer
stat the power-cutover marker. The helper now matches the contract
and repairs a drifted mode; the hermetic test pins the behaviour by
drifting the dir and running the helper.

Note: Fixed: toggling the network kill switch locked the shared state
directory to root
The power-cutover preflight statted the adoption marker as the user
and treated anything but ENOENT as fatal, so a box whose
/var/lib/ryoku sat at 0700 aborted the whole update with "inspect
package power cutover state: permission denied". An unreadable marker
is now a question for root through sudo -n test -e, and a probe that
cannot run reads as absent: the helper is idempotent, and skipping a
needed cutover costs more than a redundant one.

Note: Fixed: ryoku update aborting with permission denied on the
power cutover check
A box retiring its source checkout with \`ryoku track unstable\` had no
ryoku-desktop installed, so the installed-only move set was empty: the
switch succeeded, installed nothing, and left the box with no lane to
update from. The move now adds the umbrella plus the active compositor
variant, the same pair the ISO installer lays.

Note: Fixed: ryoku track unstable could leave a dev box with no desktop
packages installed and no way to update.

Co-Authored-By: omp <[email protected]>
`ryoku wm use <compositor>` installed the variant package with a bare
`pacman -S`, the one ryoku transaction without --overwrite for the
system paths the ISO installer and deploy.sh seed unowned. On a box
seeded that way the transaction aborts ("exists in filesystem") and the
GUI compositor install fails. The glob now also covers the boot hook,
the modules-load and udev rules, the lockscreen bundle, and the
default-apps mimeapps map, and the doctor's stray list is that glob
split, so the two cannot drift.

Note: Fixed: installing another desktop (e.g. Mango) from the Hub could
fail with file conflicts and install nothing.

Co-Authored-By: omp <[email protected]>
The MangoWM session failed the promises the desktop switch makes. Five
root causes, each fixed at the seam that owns it:

- The provider read monitor modes through wlr-randr but dropped the
  refresh half of every mode string, and the variant package never
  installed the tool, so the Hub's Displays page had no modes to offer
  and a generated monitorrule could pin the panel to its lowest rate.
  Modes now carry WxH@Hz end to end, an unknown refresh is omitted so
  mango keeps its EDID-preferred mode, wlr-randr ships with the
  variant, and a failed live reload is reported instead of swallowed.
- A Hub save of window-manager settings committed its dirty state
  before the backend finished and discarded the provider's reload
  error, so every failed save looked like a successful no-op. The save
  now commits on exit zero, reports stderr otherwise, and the backend
  surfaces the reload failure.
- A machine that ran another compositor first could carry its IPC
  handle in the systemd user manager, and the seam resolves a live
  handle before the desktop name, so a mango session could be served
  hyprland caps, keybinds, config paths, and a Plugins page. The login
  cutover now clears every handle the seam names (new ryoku wm handles
  verb), and the Hub marks a provider running only when it is live.
- Capability gating was fail-open before the first settings frame, so
  hyprland-only pages rendered under mango; supports() now requires an
  explicit true.
- The shell built its workspace list from ext-workspace protocol
  objects and dropped provider workspaces that have none; the provider
  frame is now authoritative and the protocol only enriches it, so bar
  styles render the same on every compositor. Mango also gained its
  special workspace in the frames, one focused window in focus order,
  and honest layer-rule choices.

Note: Fixed: the Mango desktop now applies Hub settings live, detects
displays correctly, and keeps the shell, Hub and bar styles consistent.

Co-Authored-By: omp <[email protected]>
The mango seam commit added a function to ryoku/wm/detect.go, which the
installer links through the go.mod replace. The committed binary
predates that change, so a fresh build differs from the shipped bytes.
Rebuilt from the current source and refreshed the checksum; the pair
must always land together or install.sh refuses its own download.
Super+Escape opens the left controls sidebar and Super+S opens the right
companion sidebar. The panels ride the background layer with an animated
exclusive zone while the desktop surface slides over them, so the sidebar
reads as resting underneath the screen; a native Ryoku.SidebarFx depth
edge paints the desktop's cast shadow at the moving seam. Cards use the
Hub's Ryoku.Ui language, micro-animate on open and tab switch, and the
sidebarCard plugin host lets contributors ship their own. Hub > Desktop
gains a Sidebars tab for width, motion, depth, push, parallax, and card
order; the doctor retires the old frame records.

Note: New: push-aside sidebars open with Super+Escape on the left and Super+S on the right
Note: Removed: the old quick-settings menu and stash card
? '<button class="btn btn-ghost" data-act="unwire" data-id="' + escapeHtml(a.id) + '">UNWIRE</button>'
: '<button class="btn btn-primary" data-act="wire" data-id="' + escapeHtml(a.id) + '"' +
(a.present ? "" : " disabled") + ">WIRE</button>";
? '<button class="btn btn-ghost" data-act="unwire" data-id="' + esc(a.id) + '">Unwire</button>'
: '<button class="btn btn-primary" data-act="wire" data-id="' + escapeHtml(a.id) + '"' +
(a.present ? "" : " disabled") + ">WIRE</button>";
? '<button class="btn btn-ghost" data-act="unwire" data-id="' + esc(a.id) + '">Unwire</button>'
: '<button class="btn btn-primary" data-act="wire" data-id="' + esc(a.id) + '"' +
'<div class="agent-id"><span class="agent-name">' + escapeHtml(a.name) + "</span>" +
'<span class="agent-file">' + escapeHtml(a.file || "") + "</span></div>" +
'<div class="agent-state">' + skill + stateChip + action + "</div></div>"
'<div class="card acard" data-id="' + esc(a.id) + '">' +
const dis = b.available ? "" : " disabled";
return '<button class="' + cls + '" data-chat="' + escapeHtml(b.id) + '"' + dis + ">" + escapeHtml(b.name) + star + "</button>";
return '<button class="' + cls + '" data-chat="' + esc(b.id) + '"' + dis + ">" + esc(b.name) + star + "</button>";
.map(
(m) =>
'<span class="chip" title="' +
esc(m.path) +
table(
[
["Schedule", (r) => '<span class="mono">' + esc(r.schedule) + "</span>"],
["Command", (r) => '<span class="mono muted" title="' + esc(r.command) + '">' + esc(r.command) + "</span>"],
[
["Name", (r) => '<span class="mono">' + esc(r.name) + "</span>"],
["", (r) => (r.state === "running" ? '<span class="state ok">up</span>' : '<span class="state idle">' + esc(r.state) + "</span>")],
["Image", (r) => '<span class="mono muted" title="' + esc(r.image) + '">' + esc(r.image) + "</span>"],
.map((t) => {
const [cls, label] = sev[t.severity] || sev.info;
return (
'<div class="card tip tip-' + esc(t.severity) + '" data-fix-scope>' +
.map((f) => {
const [cls, label] = DOC_STATE[f.status];
return (
'<div class="card tip doc-' + esc(f.status) + '" data-fix-scope>' +
}
function fileRow(f) {
return (
'<button class="vfile' + (current === f.path ? " active" : "") + '" data-p="' + escapeHtml(f.path) + '">' +
@aethctl aethctl closed this Oct 2, 2026
@aethctl

aethctl commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

pls ignore this, i closed the pr :/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants