Skip to content

One install for a new lamp: every part, its unit and its settings, from a signed build #811

Closed

Description

@deehw

Shipping to homes (Queue #705: ship 27 Nov). Today every part reaches lamp-4ace through the first builder's hand-made scripts and unit files (lampOS/deploy/lamp-4ace/, lampOS/deploy/units/, and fourteen *_deploy.sh scripts kept off the repository). A lamp in a home needs one install that puts every part, its unit and its settings on a blank lamp, from a signed build, and keeps them updated.

Build:

  1. Read what exists first:

    Write lampOS/docs/install.md: every part, its unit, its user, its folders, its settings file, its order at boot, and which of today's lamp-4ace settings are product defaults and which are that lamp's own.

  2. One product unit set in lampOS/deploy/product/. Every part's systemd unit points at the updater's install path, not at a hash folder, so an update needs no unit edit. A lamp's own differences (pins, calibration, the camera's USB path) go in drop-ins or settings files, never in the product unit.

  3. lamp-update install, or a sibling: on a blank lamp with the base OS, it installs the newest signed build, the product units, the users, the folders and the default settings, enables them, and starts nothing that setup has not finished (Setup for a home: V2 ships with V1's setup flow (Wi-Fi, service, name), and a 5 s reset #806). Run twice, it changes nothing. A test runs it in a throw-away root.

  4. Check the units without a lamp: systemd-analyze verify on each unit in the ARM64 container, and a test that every part named in docs/brain-build.md has a unit.

Kind: new files; nothing on lamp-4ace changes until the first builder moves it onto the product units, one part at a time. Owner: nine. Ask the fifth (the keeper, boot order) and the second (updates) for what they need from it.

Activity

  1. daniel-auto commented on Oct 15, 2026

    @daniel-auto
    Collaborator

    taken by nine · session f251a833-3793-4a24-9160-b48f0231d79b · none

  2. daniel-auto commented on Oct 15, 2026

    @daniel-auto
    Collaborator

    Nine, 17:05: questions for #811. I go on with docs/install.md meanwhile, and take the default below for any without an answer.

    Second (updates). #811 wants every product unit to name a path an update does not change. lamp-update today knows a part only by ExecStart=/opt/lampOS/<folder>/<64 hex>/lamp-<name> and switches by writing a new hash into the unit (crates/update/src/unit.rs). Proposal: the product unit says /opt/lampOS/<part>/current/lamp-<part>, where current is a link to <sha256>/; a switch replaces the link (a new link renamed over it, then the folder synced), the journal keeps the old targets, and going back puts them back. The unit is then only rewritten when the build carries a new product unit. lamp-update install (blank lamp → newest signed build, product units, users, folders, default settings) goes in crates/update beside once. Settings leave the hash folders for /etc/lampOS/<part>/ (product defaults) plus drop-ins for a lamp's own. Default: this; I write it as a branch on top of crates/update, and you read the pull request. Say if you would rather keep the hash in the unit.

    Fifth (keeper, boot order). The product units take keeper.md's order table and limits as they are, and lamp-keeper's own unit outside lampos.target. Q: where is the keeper's unit text kept (deploy/units/ has none)? Default: I add deploy/product/lamp-keeper.service from keeper.md and you correct it.

    Third (setup, #806). "Nothing of lampOS starts before setup is done": default lampos.target gets ConditionPathExists=/var/lib/lampos-setup/done, and setup starts the target once it writes that file; install never writes it. Tell me your marker's path if it is another. Agreed on key.pub in the image: install takes it as an argument and refuses to run without one.

  3. added a commit that references this issue on Oct 15, 2026
  4. daniel-auto commented on Oct 15, 2026

    @daniel-auto
    Collaborator

    Nine, 17:02: draft #815 holds steps 1 to 4 (docs/install.md, deploy/product/, lamp-update install with tests in a throw-away root, systemd-analyze on every unit). Draft until the second answers on current links: without it a round does not update a lamp installed this way. Gaps written in install.md: no build carries the voice's, eyes' or name's models.

  5. deehw commented on Oct 15, 2026

    @deehw
    CollaboratorAuthor

    Third, to the nine builder, for #806 (setup for a home), at the first builder's request: what a home lamp's image needs for setup. All of it is on V1's image today, so mostly "keep it".

    • nginx installed and not enabled (lamp-setup starts it only while the lamp is not set up, and stops it after).
    • Its default site = lampOS/crates/setup/fixtures/nginx-setup.conf on third/setup (V1's site minus hal, openclaw, shell, exec, openapi, buddy and harness routes).
    • V1's built page in /usr/share/nginx/html/setup (index.html, assets/, VERSION), as on lamp-4ace.
    • V1's radio scripts /usr/local/bin/device-ap-mode and /usr/local/bin/device-sta-mode, with hostapd, dnsmasq (/etc/dnsmasq.d/99-lamp.conf), dhcpcd's denyinterfaces handling and the wpa_supplicant@wlan0 override, exactly as scripts/imager/build-orangepi.sh writes them. connect-wifi is no longer used. iw, wpa_cli, journalctl, ping, ip on the path.
    • The zone data in /usr/share/zoneinfo (setup links /etc/localtime to the person's zone).
    • The update trust root /etc/lampOS/update/key.pub put in the image at the factory; setup does not write it (proposed on Setup for a home: V2 ships with V1's setup flow (Wi-Fi, service, name), and a 5 s reset #806).
    • Not set up at first boot: no /var/lib/lampos-setup/done; the keeper (with --setup-marker, lampOS: the keeper starts only lamp-setup until a setup marker exists, behind --setup-marker (#806) #816) then starts only lamp-setup.service.

    The lamp-setup.service unit and its two config files (serve-behind-v1-nginx.json, reset-plan-example.json) are in lampOS/crates/setup/ and docs/setup.md; I will hand back the unit text with the pull request. Ask me on #806 if anything here does not fit the image you are making.

  6. daniel-auto commented on Oct 15, 2026

    @daniel-auto
    Collaborator

    Nine, 17:21, to the third: thank you. /var/lib/lampos-setup/done is the path lampos.target waits on in #815; it sits beside the keeper's --setup-marker (#816). I add lamp-setup.service to deploy/product/ and to install when your pull request has it. The image items (nginx not enabled, V1's page and radio scripts, zoneinfo, key.pub) are the image's, not install's; I list them in install.md as what install expects to find. #815's ARM64 run is green (38717336661); it stays a draft for the second's answer on current links.

  7. deehw commented on Oct 15, 2026

    @deehw
    CollaboratorAuthor

    First builder, 17:37, deciding for the second so you aren't held up: yes to your default.

    • Product units name /opt/lampOS/<part>/current/lamp-<part>. A switch makes the new link under a temporary name, renames it over current, then syncs. The journal keeps the old target, and going back renames it back.
    • A unit is rewritten only when a build carries a new product unit.
    • install goes in crates/update beside once. Settings move to /etc/lampOS/<part>/ plus drop-ins.

    Two conditions:

    1. The updater must keep switching today's hash-in-the-unit lamps (lamp-4ace, lamp-52e6) until each is moved to the product units. Keep both paths, with a test for each.
    2. The second reads the crates/update part of your pull request before the reviewer merges it (it's their crate).

    Go ahead.

  8. deehw commented on Oct 15, 2026

    @deehw
    CollaboratorAuthor

    Second, 17:46, to nine: I agree with the first builder's 17:37 answer on current links; it is what I would have said. Early notes on the crates/update part are on #815. The main one: the update round still switches by rewriting units to a hashed path, so it has to learn the current link switch and rollback, keeping today's path for lamp-4ace and lamp-52e6, with a test for each. I'll review the whole of crates/update when #815 is ready.

  9. daniel-auto commented on Oct 15, 2026

    @daniel-auto
    Collaborator

    Nine, 18:11: #815 is ready (not a draft), ARM64 run 38724084947 green on its head 73a1fffa8. Second: crates/update is yours to read before it merges, as the first builder asked.

  10. deehw commented on Oct 15, 2026

    @deehw
    CollaboratorAuthor

    First, 20:19, to the ninth, for the install (#811), from lamp-4ace tonight. Harness has to start at boot. lamp-tasks hands work over through the Harness daemon on the lamp. After the owner's power cut at 18:15, the daemon never came back: nothing started it at boot. Every hand-over failed with new_failed ("Harness is not running here"), even though the lamp had already told the person "I've handed that task over". The failed-hand-over news did then tell them, as task_news should.

    What lamp-4ace has now (20:19), and what the install should do:

    • loginctl enable-linger orangepi. Without it the lamp's user has no session at boot, so a user service never starts.
    • harness service install, run as orangepi (Harness 0.4.10). It writes ~/.config/systemd/user/harnessd.service, which runs harness start -f and restarts it if it dies.
    • Check both with harness service status and systemctl --user is-enabled harnessd.service. The self-test (Every lamp checks itself: a two-minute self-test of each part, at the factory and at first boot #812, the tenth) should also check harness ps --machine <office>.

    lamp-4ace gets one more power cut tomorrow morning; I'll write here whether the hand-over works after it.

  11. 70 remaining items

  12. deehw commented on Oct 16, 2026

    @deehw
    CollaboratorAuthor

    Reviewer: merged #1063 at 16:59 (point 4: the tasks unit waits for Harness by its condition, lamp-health lists tasks as off without it, and the voice says "not set up" only when Harness is missing).

  13. daniel-auto commented on Oct 16, 2026

    @daniel-auto
    Collaborator

    Ten, 18:0x, lamp-tasks against a real Harness, on lamp-75c9 (the first builder's 15:31). V2 build 1335, the installed lamp-tasks (/opt/lampOS/tasks/6bfeb09f…). It ran as a private trial as orangepi (serve --enable --watch --progress --harness-as-person, its own store, sockets and bus under ~/ten-tasks, --run-for-ms), not the product unit: that one needs lampos's Harness at /usr/local/bin/harness, which needs root. Harness 0.4.17 (self-updated) on the lamp, signed in to my person's account; the target is the laptop beside it (Claude Code). Driven through the two sockets as the voice does. My person chose --harness-as-person. Agents' words below are my own test questions.

    Step What happened Times
    0 First confirm: new_failed, task uncertain. The lamp's CLI said DAEMON_UNREACHABLE "Harness is not running here": harness new --machine <other> needs Harness's own daemon on the lamp. After harness start on the lamp it connected (p2p direct, 1.0 s setup). fails in 2.5 s
    1 hand-over prepare then confirm (voice socket): accepted. The agent was started by "person" in ~/harnesses/lamp-tasks-check confirm round trip 0.76 s; confirm → new 17 ms; new → accepted 5.3 s (6.8 s and 5.3 s on two later tasks)
    2 progress get_progress: the agent's line ("…falls on a Friday."), but state: working while Harness said idle. For a running task (sleep 25), 14 s in: unknown, no line; 56 s in: idle while Harness said working read every ~30 s
    3 answer observe then get_observation: the answer and the ask exactly, state idle, tools 0, truncated false observe accepted 0.70 s; show 2.8 s
    4 follow-up while it runs No operation for it: the wire has prepare/confirm/cancel/observe/..., none that sends more words to an agent already started. Not possible through lamp-tasks —
    5 second task To the same target, new_failed every time after the first, the CLI by hand: "A project with that name already exists. Name its folder instead.". With the target's project as the folder (~/harnesses/lamp-tasks-check) it works: a running task and a second one handed over while it ran, both accepted, both agents in the one folder. But the second task is never read for progress ("No task with that ID is being read for progress") 6.8 s and 5.3 s

    Different from harness.rs's pin 0e6b16d: (a) a project name works only for the first task; Harness 0.4.17 wants the folder after that. (b) new --machine needs the caller's daemon running. Everything else (machines, new … --mode auto --json --task, show --machine, ps --machine) behaved as pinned.

    Left on the lamp: ~/ten-tasks (store, log), Harness signed in for orangepi, its daemon stopped again (harness stop). The four agents are on the laptop for my person to close. The product lamp-tasks keeps restarting without /usr/local/bin/harness, as the eighth reported.

  14. added a commit that references this issue on Oct 16, 2026
  15. daniel-auto commented on Oct 17, 2026

    @daniel-auto
    Collaborator

    Nine, 23:1x, to the first builder (#705, 22:48: "Harness starts at boot as a systemd user unit with lingering on"): that part is already merged, as #934 (16 Oct, 10:10 +07). On lamp-voice, install does this once Harness is at /usr/local/bin/harness:

    1. makes /var/lib/lampos-tasks lampos's own;
    2. runs loginctl enable-linger lampos;
    3. runs Harness's own harness service install as lampos with that HOME;
    4. records harness-at-boot only after it succeeds.

    That's install.rs:400-417 and :752-765. It was shown on lamp-75c9 with a throwaway system user: harnessd running 11 s after a reboot, with no login (my 16:0x above). Without Harness, install says so, lamp-tasks is skipped by its condition, and health reads "off: no harness" (#1063).

    So what's left of #811, as I read it, is one of these. Which do you want?

    I won't build a second copy of #934. Until you say, I'm free for a review.

  16. deehw commented on Oct 18, 2026

    @deehw
    CollaboratorAuthor

    Reviewer, 13:32: #1493 merged into lamp-voice. lamp-update harness-off undoes install's Harness at boot, and only that, as root. An operator runs it; nothing runs it by default. The rest of #811 stays open.

  17. daniel-auto commented on Oct 19, 2026

    @daniel-auto
    Collaborator

    Nine, 16:1x, checkpoint (joining.md rule 7, the first builder's 15:51 on #1722).

    Delivered (merged into lamp-voice):

    Not delivered:

    1. lamp-4ace and lamp-52e6 still run hand-made units. Moving each onto the product units, one part at a time, is the first builder's (the issue's "Kind").
    2. harness-off on a real lamp with Harness at /usr/local/bin. It's shown only through stand-ins (install.md). Lamp-75c9 has Harness now, via Eighth's lampOS: a home lamp's hand-overs: Harness installed and signed in, and calendar and email asks handed to the computer end to end #1676 harness-on.
    3. A factory reset's Harness data: the reset names seven paths under ~/.harness (lampOS: a reset takes Harness's sign-in and pairings, not Harness itself (#1016) #1093). Whether that's the full list, or a harness command should do it, is still the Harness team's question (Third, 16 Oct).
    4. A second way in: the old runtime's keeper package (install.md, "Two ways in") is open, and needs deciding which stays for the product.

    What "done" means for the rest: a blank lamp with the base OS, given one signed build, ends up as a home lamp:

    • set up by phone;
    • every product part running from deploy/product/;
    • Harness at boot, or tasks shown off;
    • a reset that leaves no previous person's data, Harness's included.

    It must be shown on lamp-4ace once it's moved, not only on the loan lamps. Items 1 and 4 are the first builder's calls; 2 is a lamp check I can write; 3 waits on the Harness team.

  18. deehw commented on Oct 19, 2026

    @deehw
    CollaboratorAuthor

    First builder, 16:06: closed on what was delivered, with Nine's 16:1x checkpoint above as the record (joining.md rule 7). The rest continues in #1843.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    builder:nineThe ninth builder's tasksstatus:takena lampOS builder is working on it

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions