Skip to content

feat(recipes): add remote recipes - #67

Merged
NovusEdge merged 42 commits into
mainfrom
feat/remote-recipes
Sep 5, 2026
Merged

NovusEdge merged 42 commits into
mainfrom
feat/remote-recipes

Conversation

@NovusEdge

@NovusEdge NovusEdge commented Sep 5, 2026 •

Copy link
Copy Markdown
Owner

What changed

Recipes can come from git. stoat recipe add <name|url>[@ref] clones one recipe repository into the recipe cache and pins its commit in stoat.lock; recipe lock, recipe sync, recipe update, recipe rm and recipe search manage the lock, the cache and the curated index. Two scopes: home (~/.stoat) and project (the directory holding stoat.toml). recipe list reports every manifest in shadow order with its scope, source, ref and commit, and the JSON contract goes to 3 for that shape change. stoat doctor reports git as an optional dependency. The MCP server gains search_recipes, add_recipe, update_recipe and remove_recipe. New package internal/gitx wraps the git subprocess.

Why

Spec docs/specs/2026-09-04-remote-recipes-design.md. A recipe existed only when bundled or copied by hand into ~/.stoat/recipes/. A lockfile at two scopes lets a repository pin the recipes its VMs need, which the project file spec builds on.

Tests run

  • go build ./... && go vet ./... && go test ./... && golangci-lint run ./... clean at the branch tip, after the rebase onto feat(recipes): add recipe contract v3 #65.
  • Three chunk reviews plus a final review on the branch before the rebase.
  • Opus review of the full diff against the spec: MERGEABLE-AFTER-FIXES. Five findings fixed as commits 06afe41, 7724f06, 47ed9c9, f9643a6, cb6d54e.
  • Live gate at 631eeb9 on Debian 13 cloud, evidence in the comment below: recipe add by file URL at home and project scope, lock and cache sync, an apply from the project cache, healthy wait, in_use refusal, cleanup. The gate found one deadlock, fixed in 631eeb9: recipe rm took its own scope lock twice through core.List.

Two pre-existing behaviours observed, logged as follow-ups and out of scope here: up --json on a cloud VM returns before the boot-time apply, and wait --applied reads a host apply log the cloud path never writes.

Rebase notes

Rebased from the shared Wave B foundation onto main after #65. Four conflicts resolved by hand: the recipe subcommand union in internal/cli/grammar.go, the recipe rows and contract line in docs/reference/json.md, go.mod, and internal/core/apply.go, where the hash helpers now resolve a script through the manifest's own directory (m.ScriptHash) so a project recipe that shadows a global one hashes the right file.

Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
@NovusEdge NovusEdge added enhancement New feature needs-live-boot Cannot be verified by agents; needs a real Alpine boot recipes bundled or index recipes labels Sep 5, 2026
@NovusEdge NovusEdge self-assigned this Sep 5, 2026
@NovusEdge NovusEdge added needs-live-boot Cannot be verified by agents; needs a real Alpine boot recipes bundled or index recipes labels Sep 5, 2026
@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
Signed-off-by: NovusEdge <novusedge0@gmail.com>
recipes.RemoveChecked calls the users callback while holding the scope lock exclusively. core.List resolved every VM's manifests through recipes.ManifestFor, which takes the same flock on a second descriptor, so stoat recipe rm hung whenever any VM listed a recipe.

Signed-off-by: NovusEdge <novusedge0@gmail.com>
@NovusEdge

Copy link
Copy Markdown
Owner Author

Remote recipe live gate: PASS

The revised cloud checks passed: tsprobe.applied=true, healthy wait reached its target in 677 ms (90-second timeout), and the console shows the recipe's Tailscale installation completing. Removal was refused with in_use while the VM referenced the recipe, then succeeded after VM cleanup.

Earlier home/project add, list, and sync evidence is from 5b340ee. The binary for resumed step 7 onward is 631eeb9, fix(core): read vm.toml only in RecipeUsers, 42 commits over origin/main. Binary build metadata reports that revision and vcs.modified=false; the feature worktree is clean.

up --json returns after starting the VM, before foreground host auto-apply.

Fixture and scope evidence

Source: file:///tmp/stoat-live-recipes/tsprobe, copied from bundled Tailscale with manifest name tsprobe matching the repository basename. The live fixture is v3, commit 18e98e8612bce4c752480c1eab077b76280cd14c: the entire [params.authkey] table was removed; scripts and [health] (tailscale version, 30-second timeout) were retained. No authkey, --set, or --secret was supplied.

Home-scope tests used tsprobe@v1, commit 765c2a364b845273deb9089035e04d250964224a. The isolated home lock had the matching source/ref/full commit. Project add created stoat.lock, .stoat/recipes/tsprobe, and the .stoat/ ignore rule. The generated project cache was moved aside after the environment refused recursive deletion; sync was run with .stoat absent and rebuilt it at the locked commit. The v3 project lock and cache were also checked against the v3 commit before boot; the global v1 pin remained installed.

Optional index search failed with the envelope below, the allowed unavailable-index exception.

Steps 5–6: exact commands and JSON at 5b340ee

Global working directory: /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/remote-gate.bDwkFe/tsprobe

env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat recipe add file:///tmp/stoat-live-recipes/tsprobe@v1 -y --json

Exit 0.

{"v":3,"type":"result","cmd":"recipe","ok":true,"data":{"name":"tsprobe","source":"file:///tmp/stoat-live-recipes/tsprobe","ref":"v1","commit":"765c2a364b845273deb9089035e04d250964224a","scope":"global"}}
env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat recipe list --json

Exit 0.

{"v":3,"type":"result","cmd":"recipe","ok":true,"data":{"roots":[{"path":"/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/recipes","scope":"global"},{"path":"/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/recipes","scope":"local"},{"path":"/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/recipes","scope":"bundled"}],"recipes":[{"name":"cloud-probe","description":"disposable cloud delivery verification","scope":"local","source":"","ref":"","commit":""},{"name":"devtools","description":"git, a compiler, an editor and basic fetch tools","scope":"bundled","source":"","ref":"","commit":""},{"name":"docker","description":"Docker engine and the compose plugin","scope":"bundled","source":"","ref":"","commit":""},{"name":"tailscale","description":"Tailscale daemon, installed and started (join manually)","scope":"bundled","source":"","ref":"","commit":""},{"name":"tsprobe","description":"Tailscale daemon, installed and started (join manually)","scope":"global","source":"file:///tmp/stoat-live-recipes/tsprobe","ref":"v1","commit":"765c2a3"},{"name":"xfce","description":"XFCE desktop with autologin startx on tty1","scope":"bundled","source":"","ref":"","commit":""}]}}
env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 GIT_TERMINAL_PROMPT=0 /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat recipe search --json

Exit 1.

{"v":3,"type":"result","cmd":"recipe","ok":false,"error":{"code":"internal","message":"git clone --quiet --depth 1 -- https://github.com/novusedge/stoat-recipes /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/.stoat-index-stage-2129083916: exit status 128: fatal: could not read Username for 'https://github.com': terminal prompts disabled"}}

Project working directory: /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/remote-gate.bDwkFe/project.041WQP (initially empty stoat.toml; initialized Git for the ignore rule).

env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat recipe add file:///tmp/stoat-live-recipes/tsprobe@v1 -y --json

Exit 0.

{"v":3,"type":"result","cmd":"recipe","ok":true,"data":{"name":"tsprobe","source":"file:///tmp/stoat-live-recipes/tsprobe","ref":"v1","commit":"765c2a364b845273deb9089035e04d250964224a","scope":"project"}}
test ! -e /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/remote-gate.bDwkFe/tsprobe/project-cache-before-sync && mv /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/remote-gate.bDwkFe/project.041WQP/.stoat /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/remote-gate.bDwkFe/tsprobe/project-cache-before-sync && test ! -e .stoat

Exit 0.

No output.

env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat recipe sync --json

Exit 0.

{"v":3,"type":"result","cmd":"recipe","ok":true,"data":{"recipes":[{"name":"tsprobe","source":"file:///tmp/stoat-live-recipes/tsprobe","ref":"v1","commit":"765c2a364b845273deb9089035e04d250964224a","scope":"project"}]}}

Resumed step 7: Debian 13 cloud boot

All commands below ran from /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/remote-gate.bDwkFe/project.041WQP unless stated otherwise. Guest: 2048 MiB, 2 CPUs, headless/VNC, recipe tsprobe from the project cache.

The previously blocked removal completed in 126 ms at the new tip. The v2 fixture was rejected because an optional authkey had no default; v3 removed that parameter table as directed and was accepted. The original v1 VM had been removed before this v3 VM was created.

New-tip build, fixture replacement, create/up, and apply output

Build working directory: /home/novusedge/vms/stoat/.worktrees/remote-recipes.

env GOMAXPROCS=2 GOFLAGS=-p=2 nice -n 10 go build -o /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat ./cmd/stoat

Exit 0. No unit gate was rerun.

env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 timeout --signal=TERM --kill-after=5s 30s /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat recipe rm tsprobe -y --json

Exit 0.

{"v":3,"type":"result","cmd":"recipe","ok":true,"data":{"name":"tsprobe","scope":"project"}}
env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 timeout --signal=TERM --kill-after=5s 30s /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat recipe add file:///tmp/stoat-live-recipes/tsprobe@v2 -y --json

Exit 1.

{"v":3,"type":"result","cmd":"recipe","ok":false,"error":{"code":"invalid_spec","message":"invalid recipe tree: tsprobe.authkey: needs a default or required = true"}}
env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 timeout --signal=TERM --kill-after=5s 30s /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat recipe add file:///tmp/stoat-live-recipes/tsprobe@v3 -y --json

Exit 0.

{"v":3,"type":"result","cmd":"recipe","ok":true,"data":{"name":"tsprobe","source":"file:///tmp/stoat-live-recipes/tsprobe","ref":"v3","commit":"18e98e8612bce4c752480c1eab077b76280cd14c","scope":"project"}}
env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat create remote-tsprobe-v3-041wqp --image debian-13 --ram 2048 --cpus 2 --recipes tsprobe --json

Exit 0.

{"v":3,"type":"result","cmd":"create","ok":true,"data":{"vm":{"name":"remote-tsprobe-v3-041wqp","os":"debian","mode":"cloud","backend":"cloudinit","state":"stopped","cpus":2,"ram_mb":2048,"disk":"8G","share":"","recipes":["tsprobe"],"ssh_port":2203,"ssh_user":"stoat","installed":false,"forwards":[],"allow_exec":true,"display":"vnc"}}}
umask 077 && env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 GOMAXPROCS=2 nice -n 10 timeout --signal=TERM --kill-after=30s 900s /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat up remote-tsprobe-v3-041wqp --json > /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/remote-gate.bDwkFe/tsprobe/v3-631eeb9/up.txt 2>&1

Exit 0.

{"v":3,"type":"result","cmd":"up","ok":true,"data":{"vm":{"name":"remote-tsprobe-v3-041wqp","os":"debian","mode":"cloud","backend":"cloudinit","state":"running","cpus":2,"ram_mb":2048,"disk":"8G","share":"","recipes":["tsprobe"],"ssh_port":2203,"ssh_user":"stoat","installed":false,"forwards":[],"allow_exec":true,"display":"vnc"}}}

One explicit plain apply was also run after up --json; output was captured in the file named by the command:

umask 077 && env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 GOMAXPROCS=2 nice -n 10 timeout --signal=TERM --kill-after=15s 240s /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat apply remote-tsprobe-v3-041wqp > /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/remote-gate.bDwkFe/tsprobe/v3-631eeb9/apply-output.txt 2>&1

Exit 0.

applying recipes to remote-tsprobe-v3-041wqp...
remote-tsprobe-v3-041wqp: recipes applied

The earlier wait --until applied timed out; it was no longer pending when the corrected probe instructions arrived. That host-log-based wait is not used as the cloud gate. The host apply log is empty because cloud-init applies inside the guest. The VM had been stopped and preserved; its first-boot console tail was saved before restarting the same guest with --no-apply for the healthy check.

Revised cloud probes: get, healthy wait, and console

Saved first-boot console command (exit 0; 200 lines captured). Installation/completion excerpts from that capture:

env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat logs remote-tsprobe-v3-041wqp --which console -n 200
[   57.525382] cloud-init[529]: Installation complete! Log in to start using Tailscale by running:
[   88.467097] cloud-init[529]: tailscale installed and tailscaled running.
[   88.587742] cloud-init[529]: Cloud-init v. 25.1.4 finished at Sat, 05 Sep 2026 10:07:51 +0000. Datasource DataSourceNoCloud [seed=/dev/sr0].  Up 88.58 seconds

Restarted the preserved VM without reapplying:

env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 GOMAXPROCS=2 nice -n 10 timeout --signal=TERM --kill-after=10s 120s /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat up remote-tsprobe-v3-041wqp --no-apply

Exit 0.

starting remote-tsprobe-v3-041wqp...
remote-tsprobe-v3-041wqp started (ssh :2203)
display: no usable graphical session on this host, so the screen
  is on VNC instead; attach to watch it
display: no qemu window; the screen is on /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/remote-tsprobe-v3-041wqp/vnc.sock
  attach with: gvncviewer /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/remote-tsprobe-v3-041wqp/vnc.sock

Applied-state result:

env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat get remote-tsprobe-v3-041wqp --json

Exit 0.

{"v":3,"type":"result","cmd":"get","ok":true,"data":{"vm":{"name":"remote-tsprobe-v3-041wqp","os":"debian","mode":"cloud","backend":"cloudinit","state":"running","cpus":2,"ram_mb":2048,"disk":"8G","share":"","recipes":["tsprobe"],"ssh_port":2203,"ssh_user":"stoat","installed":false,"forwards":[],"allow_exec":true,"display":"vnc","health":"unknown","recipes_detail":[{"name":"tsprobe","applied":true,"version":"","at":"2026-09-05T10:09:40Z","health":"unknown","params":{},"outputs":{}}]}}}

Live health result:

env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat wait remote-tsprobe-v3-041wqp --healthy --timeout 90s --json

Exit 0.

{"v":3,"type":"result","cmd":"wait","ok":true,"data":{"reached":true,"until":"healthy","vm":"remote-tsprobe-v3-041wqp","waited_ms":677}}

get retains stored health:"unknown"; the separate healthy wait above returned ok:true/reached:true. These are reported separately, not as a stored health:"ok" claim.

Host apply-log tail command:

env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat logs remote-tsprobe-v3-041wqp --which apply -n 30

Exit 0.

No output.

Superseded host-log probe, retained here for the audit trail (not rerun):

env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat wait remote-tsprobe-v3-041wqp --until applied --timeout 8m --json

Exit 1.

{"v":3,"type":"result","cmd":"wait","ok":false,"error":{"code":"timeout","message":"context deadline exceeded"}}

Step 8: in-use refusal and cleanup

The refusal's exit 1 is expected. All cleanup commands exited 0. The VM directory and project recipe cache are now absent, and the project declaration/lock no longer contain tsprobe. VM deletion is not recoverable through Stoat; the source fixture and evidence remain saved.

Exact removal and cleanup commands/results
env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 timeout --signal=TERM --kill-after=5s 30s /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat recipe rm tsprobe --json

Exit 1.

{"v":3,"type":"result","cmd":"recipe","ok":false,"error":{"code":"in_use","message":"in use: tsprobe is used by remote-tsprobe-v3-041wqp; pass --force to remove it anyway"}}
env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 timeout --signal=TERM --kill-after=10s 90s /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat down remote-tsprobe-v3-041wqp

Exit 0.

stopping remote-tsprobe-v3-041wqp...
remote-tsprobe-v3-041wqp stopped
env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 timeout --signal=TERM --kill-after=5s 30s /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat rm remote-tsprobe-v3-041wqp -y

Exit 0.

remote-tsprobe-v3-041wqp deleted
env STOAT_HOME=/home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud STOAT_GRAPHICAL=0 timeout --signal=TERM --kill-after=5s 30s /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/cloud/stoat recipe rm tsprobe -y --json

Exit 0.

{"v":3,"type":"result","cmd":"recipe","ok":true,"data":{"name":"tsprobe","scope":"project"}}

Local artifacts: /home/novusedge/vms/stoat/.worktrees/.live-wave-b.ytR40g/remote-gate.bDwkFe/tsprobe/cloud-evidence-final (including the full 200-line console capture), with original boot evidence in the adjacent v3-631eeb9/ directory. The isolated global v1 pin is unchanged. No branch code changes, unit-gate rerun, push, PR-body edit, ready transition, or merge were performed.

@NovusEdge
NovusEdge marked this pull request as ready for review September 5, 2026 10:28
@NovusEdge
NovusEdge merged commit 1897108 into main Sep 5, 2026
5 of 6 checks passed
@NovusEdge
NovusEdge deleted the feat/remote-recipes branch September 5, 2026 10:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature needs-live-boot Cannot be verified by agents; needs a real Alpine boot recipes bundled or index recipes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant