Skip to content

feat(app): sidecar bundling pipeline — first .app builds clean (#176 ticket A) - #208

Open
Dewinator wants to merge 2 commits into
mainfrom
agent/sidecar-bundle
Open

feat(app): sidecar bundling pipeline — first .app builds clean (#176 ticket A)#208
Dewinator wants to merge 2 commits into
mainfrom
agent/sidecar-bundle

Conversation

@Dewinator

Copy link
Copy Markdown
Owner

Summary

Schritt A of "fühlt sich nativ an" — replaces the launcher stub from PR #203 with a real sidecar bundling pipeline. After this lands, cargo tauri build produces a working mycelium.app on the developer Mac.

Locally validated: 151 MB .app under target/release/bundle/macos/mycelium.app, launches successfully, opens window at http://127.0.0.1:8787 (existing dashboard server). Tray with 4 items appears.

Changes

  • scripts/bundle-sidecar.sh (new): copies mcp-server/dist + node_modules + supabase/migrations into app/src-tauri/sidecar-payload/. Idempotent; rebuilds mcp-server/dist if stale.
  • app/src-tauri/binaries/mycelium-mcp-aarch64-apple-darwin: stub replaced by real launcher. Locates payload (dev: ../sidecar-payload/, bundled: ../Resources/sidecar-payload/), execs node $PAYLOAD/index.js. Honest about prerequisites:
    • Requires Node on PATH (portable Node bundling = sub-task 8).
    • Inherits SUPABASE_URL / SUPABASE_KEY from the user-launchd environment (PGlite-as-primary backend = next native-app PR).
  • app/src-tauri/tauri.conf.json: bundle.resources ships sidecar-payload/. beforeBuildCommand runs the bundle script via git rev-parse --show-toplevel (robust against Tauri 2's CWD inconsistency in beforeBuildCommand resolution).
  • app/.gitignore: ignores src-tauri/sidecar-payload/ (~150 MB tree generated at build time).
  • app/README.md: status updated for iteration A — what works, what's follow-up.

Validation

cargo check                 → clean
cargo tauri build           → builds 151 MB mycelium.app
open …/mycelium.app         → window + tray, dashboard visible

Known gaps (intentional, follow-up tickets)

  • DMG packaging: final step of cargo tauri build (bundle_dmg.sh) returned non-zero on this machine. The .app itself is produced and runnable; the .dmg wrapper around it isn't. Likely fix: brew install create-dmg. Investigating in follow-up; not a blocker for "can run the native shell."
  • Self-contained Node runtime: launcher invokes node from PATH. Bundling a portable Node so the .dmg works without a system Node install is sub-task 8 (CI matrix / cross-platform).
  • PGlite as primary backend: mcp-server/src/index.ts still constructs every service against SUPABASE_URL / SUPABASE_KEY (~30 sites). Refactor to honour MYCELIUM_USE_PGLITE=1 and route all services through the in-process adapter is the next big native-app PR.
  • App icons remain solid-purple placeholders.
  • Auto-updater pubkey remains a placeholder — see app/README.md "Signing-key bootstrap".

Test plan

  • bash scripts/bundle-sidecar.sh — produces app/src-tauri/sidecar-payload/ (~136 MB)
  • cd app/src-tauri && cargo tauri build — produces target/release/bundle/macos/mycelium.app
  • open target/release/bundle/macos/mycelium.app — window opens, tray icon appears, 4 menu items, dashboard reachable

Related

🤖 Generated with Claude Code

…sub-task 3 ticket A)

Schritt A of "fühlt sich nativ an": replace the launcher stub with a real
sidecar bundling pipeline so `cargo tauri build` produces a working .app
on the developer Mac.

Locally validated: 151 MB .app under
target/release/bundle/macos/mycelium.app, launches successfully, opens
window at http://127.0.0.1:8787 (existing dashboard server). Tray with 4
items appears.

Changes:
- `scripts/bundle-sidecar.sh` (new): copies mcp-server/dist + node_modules
  + supabase/migrations into app/src-tauri/sidecar-payload/. Idempotent;
  rebuilds mcp-server/dist if stale.
- `app/src-tauri/binaries/mycelium-mcp-aarch64-apple-darwin`: stub
  replaced by real launcher. Locates payload (dev: ../sidecar-payload/,
  bundled: ../Resources/sidecar-payload/), exec's `node $PAYLOAD/index.js`.
  Honest about prerequisites: requires Node on PATH (portable Node
  bundling = sub-task 8) and inherits SUPABASE_URL/SUPABASE_KEY from
  the user-launchd environment (PGlite-as-primary backend = next
  native-app PR).
- `app/src-tauri/tauri.conf.json`: `bundle.resources` ships
  sidecar-payload/. `beforeBuildCommand` runs the bundle script via
  `git rev-parse --show-toplevel` (robust against Tauri 2's CWD
  inconsistency in beforeBuildCommand resolution).
- `app/.gitignore`: ignores src-tauri/sidecar-payload/ (~150 MB tree
  generated at build time).
- `app/README.md`: status updated for iteration A — what works, what's
  follow-up (portable Node, PGlite-as-primary, real icons,
  signing-key bootstrap).

Validation:
  cargo check                 → clean
  cargo tauri build           → builds 151 MB mycelium.app
  open …/mycelium.app         → window + tray, dashboard visible

Known gap: DMG packaging (final step of `cargo tauri build`) fails on
this machine — `bundle_dmg.sh` returned non-zero. The .app itself is
produced and runnable. Investigating in follow-up; not a blocker for
"can run the native shell".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dewinator added a commit that referenced this pull request May 4, 2026
The previous "0 PRs offen" snapshot is stale: the agent itself opened a
4-PR queue in the last 4 ticks (#208 standalone + #209#210#211 stack).
Refresh the Aktiver-Code-Bestand block to credit landed sub-tasks (#202
DATA_DIR, #203 Tauri shell, #204 CI gate, #205 migration helpers) and
add a Queue-Stand note that names the open stack, the linear merge
constraint, and the ~19 still-supabase-direct services that the
DbClient migration sub-story will work through atomically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Dewinator

Copy link
Copy Markdown
Owner Author

Merge-readiness note — CI gap is by design, not a missing run

GitHub shows mergeStateStatus: CLEAN and mergeable: MERGEABLE for this PR but no CI checks have run. That isn't a stuck workflow — it's the path-filter on .github/workflows/mcp-server-tests.yml:

on:
  pull_request:
    paths:
      - 'mcp-server/**'
      - '.github/workflows/mcp-server-tests.yml'

PR #208 changes:

  • app/.gitignore (+3 -0)
  • app/README.md (+32 -14)
  • app/src-tauri/binaries/mycelium-mcp-aarch64-apple-darwin (+45 -8)
  • app/src-tauri/tauri.conf.json (+3 -2)
  • scripts/bundle-sidecar.sh (+64 -0)

Zero mcp-server/** paths touched, so the workflow is correctly skipped. There is no CI signal to wait for — the merge gate is local sidecar-bundling validation (which the PR body documents: "first .app builds clean").

If a future PR in the native-app track wants automated coverage of the bundling pipeline, that's out of scope here — it would be a separate workflow (e.g. native-app-bundle.yml) gated on app/** + scripts/bundle-sidecar.sh. Spike noted in docs/native-ci-release-spike.md.

🤖 Posted by autonomous tick (mycelium 175th)

Dewinator added a commit that referenced this pull request May 4, 2026
…et, gen)

PR #208's sidecar-bundling pipeline drops a 136 MB `app/src-tauri/sidecar-payload/`
tree on every build, plus Rust's `target/` cache and Tauri's auto-generated
`gen/`. None were ignored, so `git status` was noisy and `git add -A` would
risk committing a hundred-plus MB of bundled deps. Ignore the three dirs.

The committed artifact (`app/src-tauri/binaries/mycelium-mcp-aarch64-apple-darwin`)
is unaffected — that path is not under any of the new patterns.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dewinator added a commit that referenced this pull request May 4, 2026
…ture) + 26h Reed-lag

Last refresh (ec8a088, tick 173) captured the 4-PR native-app cluster (#208/#209/#210/#211)
right after Reed drained #202-#207. Tick 174 then opened PR #212 (W4.1 echo-chamber row 4),
which is off-track from the native-app cluster — it's a Wave-4 fixture PR against issue #196,
not a DbClient or sidecar-bundle PR. CLAUDE.md still framed the queue as 4 PRs all in one
narrative; this corrects it to 5 PRs with the fixture-PR called out separately, and surfaces
the empirical Reed-lag (≈26 h since the 2026-05-03 10:24 UTC merge wave) so the next tick has
the right baseline for the queue-too-deep guard.

Also corrects ~21 → 22 (true grep count today on main) for the Supabase-direct service file
count, with explicit "verbleibend nach Merge: 20" so the next DbClient-migration tick can
locate the right service to pick.

No production code touched; pure CLAUDE.md doc-accuracy fix, direct-to-main per the
agent-loop convention for risk-free doc refreshes.
@Dewinator

Copy link
Copy Markdown
Owner Author

183rd-tick — empirical local validation of bundle-sidecar.sh

Ran the bundling pipeline end-to-end against this PR (head 0b63244, fresh checkout off main). Posting because the PR currently surfaces no CI checks — the only workflow (mcp-server-tests.yml) has paths: mcp-server/**, so app-only PRs like this one bypass the gate. This comment fills that empirical gap.

Results

Step Result
Cold run (build + copy) 46 s (npm run build triggered, full payload copy)
Idempotent re-run 31 s (build skipped as fresh, just wipe + recopy of 136 MB)
Final payload size 136 MB
Migrations packed 79 (matches the 79-migration-walk that's the canonical PGlite gate)
node --check sidecar-payload/index.js OK (syntax-valid module)
Launcher dev-layout resolution OKbinaries/mycelium-mcp-* finds ../sidecar-payload/index.js
Launcher command -v node OK on this Mac (Node v25.9.0)

What this validates

  • bundle-sidecar.sh runs cleanly on a developer Mac with no manual setup beyond npm already-installed.
  • The if … -nt freshness check actually triggers a rebuild when dist/index.js is stale (cold run) and skips it when fresh (re-run) — idempotent as advertised.
  • Payload layout matches what mycelium-mcp-aarch64-apple-darwin's "layout 1 (dev mode)" branch expects.
  • Bundled index.js is parseable Node ESM; nothing got mangled by the cp -R dist/. step.

What this does NOT validate

  • cargo tauri build end-to-end — would need a clean Tauri toolchain install + ~10 min on this machine; not run this tick.
  • Bundled .app actually launching — same reason. The launcher path-resolution is verified statically only.
  • Cross-platform — macOS arm64 only. Sub-task 8 (CI matrix) is the proper coverage.

Recommendation

PR is mergeable from a script-correctness standpoint. The "no CI" optic is a workflow-path-filter artefact, not a quality gap on this PR specifically — but worth tracking as sub-task 8 prep: once more app/**-only PRs land, a minimal app-tests.yml (even just bash scripts/bundle-sidecar.sh && node --check sidecar-payload/index.js) would re-establish the auto-gate. Filing a separate proposed-by-agent ticket for that would put us at backlog cap (currently 3 ungelabelte: #84, #90, #93), so noting it here instead of opening a fourth.

Dewinator added a commit that referenced this pull request May 4, 2026
…sks 1/2/3-most/4/5/7-core landed

The 09024a2 (tick 103) snapshot is two days stale: 9 of the 9 PRs in its
"recommended merge order" have merged, plus #197/#198/#201/#202/#203/#204/
#205/#206/#207 landed in the same window. Refresh the doc that "is the
canonical entry point for the native-app initiative" so a fresh reader
does not get a 79-tick-old picture.

Concrete changes:
- Phase line: "spike phase complete · gated on PR-queue drain" →
  "implementation underway · sub-tasks 1, 2, 3 (most), 4, 5, 7 (core)
  landed; 5 PRs open, ~26 h Reed-lag since #202#207".
- End-state installer list: ".dmg / .msi / .AppImage" → ".pkg / .msi /
  .AppImage", with the 2026-05-04 epic-body decision (.pkg, not .dmg)
  cited.
- Sub-task table: legend (✅ landed, 🔄 PR open, ⏳ spike-only) plus
  per-row PR status reflecting the current main:
  - Row 1 picks up #204 (79-migration walk as CI gate).
  - Row 3 picks up #202, #203, #206, #207 as landed and #208#211 as
    open. Row was "_none yet_".
  - Row 4 / 5 reframed as "inherent" (PGlite is one WASM binary;
    node-llama-cpp ships per-platform bindings).
  - Row 7 picks up #205 (Docker → PGlite migration helpers core).
- New "DbClient sub-story" subsection: 22 services touch Supabase
  directly on main; 2 in flight (Skills, SwarmPin); 20 remain after
  the open stack lands. Pattern: one service per PR.
- "Recommended merge order — open PR queue (9 deep)" section replaced
  with "Open PR queue (5 deep, all CLEAN+MERGEABLE)" — the 9 it
  documented have all merged.
- "Post-drain implementation gate" → "Post-stack implementation gate":
  parallel tracks (DbClient long-tail of 20 services + the sub-tasks
  6/8/9 release-pipeline triangle on tauri-plugin-updater per #207).

Doc-only, zero risk, direct-to-main per the standing rule for this
file shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dewinator added a commit that referenced this pull request May 4, 2026
The bird's-eye doc lagged the 2026-05-03 merge wave (PRs #202#207
landing sub-tasks 1, 2, 3-scaffold, 4, 5, 7-core) and the W3 spike
chain that settled the empirical mDNS budgets on `main`.

Changes:
- Wave 1 row: 9-PR queue → 5-PR queue (#208 sidecar bundling closing
  sub-task 3; #209#210#211 linear DbClient migration stack;
  unrelated W4.1 fixture #212). Note the 22-services DbClient sub-story
  with 2 already in flight.
- Wave 3 row: design-spike-only → 11-spike chain on `main` with named
  empirical budgets (64 KiB / 2 000 ms hostile-fetch, 5-s/3-fail
  heartbeat → 15 s eviction, ~1.3 s cold-rebrowse settle, 260 ms wake
  republish, 4 000 ms blocked-network threshold from K=10 trials).
  Cross-platform re-validation (Linux/Avahi, Windows) named as the
  open item before locking the library pick.
- Wave 1 narrative: matches the 5-PR reality, removes stale "9 PRs
  998/999 tests green" claim, keeps the queue-drain gate on sub-tasks
  6/8/9/10.

Verified: 11 spike files in experiments/swarm-discovery/, PRs
#202#207 all merged (gh pr list --state merged), 5 open PRs all
CLEAN+MERGEABLE. Refresh date bumped to 2026-05-04.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Dewinator

Copy link
Copy Markdown
Owner Author

Local validation 2026-05-04 (agent tick)

Fresh worktree of pr-208 → ran the validation steps from the test plan. Two findings worth recording:

1. Empirical sanity check ✅

After npm ci in mcp-server/, the bundle script runs cleanly:

[bundle-sidecar] payload built — 136M

Payload tree matches the spec: index.js, package.json, node_modules/, supabase/migrations/ (79 files), plus agents/, services/, tools/, types/, swarm/, middleware/, native/, util/. Size matches the PR description.

create-dmg is available via brew install create-dmg (Homebrew has it under that exact name) — that confirms the suggested fix for the known DMG-bundling gap.

2. Step-ordering bug in scripts/bundle-sidecar.sh ⚠️

On a fresh checkout (no mcp-server/node_modules yet), the script fails:

[bundle-sidecar] mcp-server build needed — running npm run build
> mycelium-mcp-server@0.1.0 build
> tsc
sh: tsc: command not found

Cause: step 1 invokes npm run build (which needs tsc from node_modules/.bin/) before step 2 ensures node_modules/ exists.

After manually running npm ci once, the script works on every subsequent run. So this only bites a fresh clone (CI, new contributor, or a clean re-bundle after rm -rf mcp-server/node_modules).

Trivial fix: swap the two blocks — install deps first, then build. One-line move; same logic. Happy to roll into a follow-up commit on this PR if you want, otherwise it can ride along with sub-task 8 (CI matrix) where this would surface anyway.

Out of scope / not validated here

  • cargo tauri build (would require ~10–15 min Rust compile; sidecar-payload generation is the testable upstream piece).
  • .dmg produced by bundle_dmg.sh (needs brew install create-dmg per PR body).
  • Tray + dashboard reachability (visual / launch-time check, can't be observed from headless tick).

— autonomous validation tick, no code changes pushed

On a fresh clone (no mcp-server/node_modules), step 1 invoked
`npm run build` before step 2 ensured deps were installed — `tsc`
lives in node_modules/.bin so the build aborted with
`sh: tsc: command not found`. The 2026-05-04 validation tick (PR #208
comment thread) flagged this as a one-line swap; this commit applies it.

Pure block-swap, same logic — node_modules check moves to step 1, build
check to step 2. Empirically re-validated:
  rm -rf mcp-server/{node_modules,dist} app/src-tauri/sidecar-payload
  bash scripts/bundle-sidecar.sh
  → npm ci (220 packages), npm run build (tsc), payload 136M ✓

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Dewinator

Copy link
Copy Markdown
Owner Author

Fix gepusht: step-ordering bug in scripts/bundle-sidecar.sh

Commit e8255eb löst den fresh-clone-Bug, den die 2026-05-04-Validation oben gemeldet hatte (tsc: command not found weil npm run build vor npm ci lief). Reiner Block-Swap, identische Logik:

  • Step 1 (war 2): node_modules-Check zuerst — sichert tsc für den Build.
  • Step 2 (war 1): Build-Check — läuft jetzt mit garantiert installierten Deps.

Empirische Re-Validation (Mac arm64, fresh-clone-Simulation)

rm -rf mcp-server/node_modules mcp-server/dist app/src-tauri/sidecar-payload
bash scripts/bundle-sidecar.sh
[bundle-sidecar] node_modules missing — running npm ci
added 220 packages, and audited 221 packages in 12s
[bundle-sidecar] mcp-server build needed — running npm run build
> tsc
[bundle-sidecar] payload built — 136M

Cold run grün, Payload-Größe identisch zu den vorigen Tick-Validierungen (136 MB, 79 Migrationen). PR sollte aus Skript-Korrektheits-Sicht jetzt ohne den fresh-clone-Stolperstein mergen.

— autonomous tick fix, no scope expansion

Dewinator added a commit that referenced this pull request May 5, 2026
… 6 status

The "Aktiver Code-Bestand" inventory was one merge-wave behind the
canonical native-app-track.md (refreshed in d0fc6ec on 2026-05-04):

- #206 (Tauri commands open_data_dir / check_for_updates / restart_app
  + tray menu) — landed, but missing from CLAUDE.md.
- #207 (tauri-plugin-updater wired to GitHub Releases latest.json) —
  landed, but missing from CLAUDE.md, AND sub-task 6 was still listed
  as fully verbleibend even though the consumer-side updater is live.

Empirical reality on main today:
- Sub-tasks 1, 2, 3 (scaffold + commands), 4, 5, 6 (updater-plugin
  app-side), 7 (core) are implemented.
- Sub-task 6 verbleibend collapses to its CI half — publishing
  latest.json + signed installers — which is paired with sub-task 8
  per docs/native-app-track.md row 6 ("⏳ spike landed, CI release
  pipeline pending").
- Sub-task 3 closes fully once #208 (sidecar bundling) merges.

Doc-only, zero risk, direct-to-main per the standing rule for this
file shape (precedent: d0fc6ec, ec8a088, f9acd10, 1962f9d).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dewinator added a commit that referenced this pull request May 5, 2026
The sub-task 9 (update-banner refit) spike was written 2026-05-02 with
approximate line ranges for the existing browser-mode update-banner code.
Re-verified empirically against main — banner JS is at 7320–7467 (function
body of `checkForUpdate()`), `/update-status` handler is at 2150–2254.
Original ranges (7315–7480, 2148–2252) were within ~5/13 lines but the
implementation tick will read these as exact references when sub-task 3
closes via #208 + DbClient stack, so tightening now avoids drift hunts.

Also de-counted the "9 PRs in flight" justification — count drifts; what
matters is the queue-full rule applies whenever the queue is full.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant