modelstudioai / modelstudioai/openwork

Migration tracker: re-found OpenWork on the Qwen Code Web Shell + Tauri architecture

Aperta
#80 2 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Lingua principale
TypeScript
Stelle
27
Fork
6
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Descrizione

Summary

Re-found OpenWork on the Qwen Code stack: fork QwenLM/qwen-code into a standalone OpenWork repository, adopt the Tauri 2 desktop shell (packages/desktop-shell) and Web Shell UI (packages/web-shell), and port OpenWork's existing product surface onto that architecture.

This issue is the master tracker. Workstreams below will be broken out into sub-issues.


1. Context: what OpenWork actually is today

Establishing this correctly matters, because it determines what "sync from upstream" can and cannot mean.

OpenWork is not a fork of Qwen Code. Its root commit 7b57e21 (2026-05-01) is a subtree extraction from eb45067f "Make backend Qwen-only", whose tree is the root-level Craft layout (apps/{cli,electron,viewer,webui}, Dockerfile.server). Qwen Code did not gain packages/desktop until 62e45c567 (#3778) on 2026-06-11 — six weeks later. eb45067f is not an ancestor of qwen-code@main.

The real topology is two siblings from a common Craft-derived ancestor:

craft-ai-agents/craft-agents-oss   (craft-agent, Electron)
            │
            ▼
   eb45067f "Make backend Qwen-only"  (2026-05-01)
            │
    ┌───────┴────────┐
    ▼                ▼
 OpenWork      qwen-code/packages/desktop
 228 commits    50 commits
 v0.1.4          v0.0.5

Current coupling to Qwen Code is narrow: qwenCodeRuntime.version: 0.15.11 in package.json, vendored from the npm tarball by scripts/vendor-qwen-code.ts, spawned as a subprocess by packages/shared/src/agent/qwen-agent.ts with ['--acp', '--channel=desktop']. Upstream CLI is now at 0.21.6 — six minors ahead.

Consequence of this migration: tracking craft-agents-oss ends. Adopting Web Shell replaces the Craft-derived UI and server layers. That is an accepted, deliberate trade — noted here so it is never a surprise.


2. Target architecture

Mirrors upstream's packages/desktop-shell:

  • Tauri 2 shell (~1,537 lines of Rust: main.rs 678, runtime.rs 547, desktop_state.rs 312) replaces Electron.
  • Shell starts the daemon on an ephemeral loopback port with a per-launch bearer token, polls /health, then opens the daemon-served Web Shell in a native window.
  • scripts/prepare-runtime.js stages runtime/qwen-code/ with a platform Node.js, the built CLI, and Web Shell under lib/web-shell/.

All artifacts build from source. prepare-runtime.js resolves sourceRoot from QWEN_CODE_ROOT or the repo root and runs npm run build -- --cli-only, --workspace=packages/webui, --workspace=packages/web-shell. No @qwen-code/* package is fetched from npm. This is deliberate — @qwen-code/web-shell is unpublished, and @qwen-code/webui on npm is 0.1.0-beta.4 against a monorepo at 0.21.6. Only third-party deps come from the registry.


3. Open questions — resolve before Phase 2

These are genuine unknowns, not rhetorical. Each can change scope materially.

  • Browser panes / CDP. apps/electron/src/main/browser-cdp.ts and browser-pane-manager.ts depend on Electron BrowserView + Chrome DevTools Protocol, backing the agent browser tools in packages/shared/src/agent/browser-tools.ts. Tauri can create multiple and child webviews, but it has no portable equivalent for the Electron BrowserView + CDP contract; WebKitGTK exposes no CDP. The current browser-agent contract may therefore be architecturally blocked. Spike before committing.
  • Web Shell variant seam. client/customization.tsx covers only presentation (markdown components, code-block/chart renderers, WelcomeHeader, theme); client/extensions/ contains one module. There is no seam for pages, navigation, or settings sections — which is most of what OpenWork adds. Decide whether to build that seam upstream first (strongly preferred) or patch Web Shell source directly.
  • Session/credential data migration. OpenWork stores product data under ~/.craft-agent/, including config.json, preferences.json, workspace/session data, and an AES-256-GCM credential file at ~/.craft-agent/credentials.enc. Its key is derived from the machine UUID; this is not a macOS Keychain re-binding problem. Session formats still differ from daemon transcripts. Decide whether to migrate each data class or explicitly document a one-way break.
  • Feature freeze policy — the parity target is currently moving. OpenWork is still shipping actively (12 commits in W30; 17 UI features in the last ~30 commits, driven by the autonomous feature loop bootstrapped in #38). If that continues through a multi-month migration, every new Electron feature adds to Phase 4's port backlog and parity recedes as it is approached. Decide one of: (a) freeze feature work on the Electron app at a named commit, (b) require new features to land on the new stack only once Phase 3 completes, or (c) accept dual-maintenance and staff for it explicitly. This must be answered before Phase 4 begins — it is the difference between a finite port and an open-ended one.

4. Phase plan

Phase 0 — De-risk (no migration work)
  • Bump qwenCodeRuntime.version 0.15.110.21.6; re-vendor; validate ACP. Note: OpenWork is on @agentclientprotocol/sdk ^0.21.0 while qwen-code 0.21.6 CLI is on ^0.14.1 — verify PROTOCOL_VERSION negotiation rather than assuming. Confirm --acp (not deprecated --experimental-acp) and --channel. Valuable independently of migration.
  • Browser-pane / CDP spike (see §3).
  • Run bun run server:prod and exercise the app in a plain browser. Whatever breaks is the true Electron-coupling inventory — 95 of 509 renderer files import window.electron / electron directly.
  • Build desktop-shell unmodified on macOS/Windows/Linux; measure real bundle size and memory before promising numbers (runtime/qwen-code/ ships Node + CLI, so the Chromium saving is partly offset).
Phase 1 — Repository foundation
  • Freeze current tree as modelstudioai/openwork-legacy (reference during porting — do not disturb the shipping product).
  • Create new OpenWork repo from QwenLM/qwen-code.
  • First commit: neutralize CI. 43 workflows, 13 release/publish. release.yml runs on daily cron; release-vscode-companion.yml fires on release: published. Also release-sdk*.yml, build-and-publish-image.yml, sync-release-to-oss.yml. Scheduled workflows are auto-disabled only in true GitHub forks, not plain repos.
  • Establish branch model: vendor/upstream (pristine mirror, never edited) → main.
  • .gitattributes: package-lock.json merge=ours, regenerate post-merge.
  • Keep all upstream packages (~18 + 10 channels). Do not prune — deleting files conflicts on every future merge.
  • Preserve upstream LICENSE/NOTICE; append attribution rather than replacing (Apache-2.0 requirement). Clean the stale Craft-era Anthropic Commercial Terms clause, which no longer applies post-eb45067f.
Phase 2 — Shell and branding
  • Fork desktop-shell → OpenWork shell with own identifier, icons, signing identity, updater keypair, endpoint.
  • Overlay, do not edit tauri.conf.json (currently com.alibaba.qwen-code, pubkey, and a QwenLM/qwen-code updater endpoint). Use tauri build --config tauri.openwork.conf.json deep-merge; verify merge semantics for the pinned Tauri version.
  • Release-time assertion that the shipped updater endpoint and identifier are OpenWork's. Shipping with Qwen's endpoint would push users into a different application — unrecoverable, so it must be enforced mechanically.
  • Add desktop-release.yml as a new file, not an edit to upstream's.
Phase 3 — Variant seam
  • Land page/route registry, settings-section registry, slot-based navigation in Web Shell (upstream where possible).
  • Establish packages/web-shell/client/openwork/ and packages/openwork-* for additive product code.
  • Start PATCHES.md ledger recording every intentional divergence in shared files, with rationale.
Phase 4 — Feature port

Port against the parity matrix (§5), one sub-issue per cluster.

Phase 5 — Data migration
  • Settings, workspace/session history, and credentials.enc migration or in-place reuse, validated with upgrade fixtures.
  • Electron → Tauri update bridge. Upstream's electron_bridge handles update delivery only — data migration is separate and ours to build.
Phase 6 — Release
  • Platform QA, signing/notarization, staged rollout, rollback plan.

5. Preservation inventory — what must not be lost

Web Shell already covers parts of Skills, MCP, Agents, Extensions/Plugins, Channels, Scheduled Tasks, themes, permissions, voice, raw-Markdown copy, prompt history, and jump-to-latest. The matrix must classify every item below as reuse / adapt / rebuild / consciously drop; do not assume either full absence or full parity.

OpenWork-owned overlay (separate release blocker):

  • Branding/distribution: openwork identity, com.alibaba.openwork, OpenWork assets/copy/co-author text, the modelstudioai/openwork updater and homepage, attribution, and an explicit decision on inherited craftagents:// deep links and the agents.craft.do viewer URL.
  • Curated skill marketplace: Bailian CLI, Bailian Docs LLM Wiki, and Spark Video Episode, including icons, examples, install sources, and descriptions.
  • Repository skills: .agents/skills/{desktop-brand-builder,desktop-develop,desktop-pet}. Port the brand builder to Tauri; rewrite or retire Electron/CDP-specific instructions; retain the pet skill only if pets remain.
  • Agent/product behavior: preserve the OpenWork contracts currently assembled in packages/shared/src/prompts/system.ts—source workflows/auth, skill discovery and precedence, product docs/preferences, permission and plan flow, MCP naming, OAuth/credential operations, rich content blocks, call_llm, browser tools, labels/status/session automation, document tools, and tool display metadata.
  • Custom agents: no repo-owned OpenWork custom-agent definitions were found. Preserve user-created Qwen agents and add a migration fixture, but do not invent a custom-agent porting scope unless one is identified.
  • Skill storage: preserve ~/.qwen/skills, ~/.agents/skills, project .qwen/skills / .agents/skills, and the OpenWork workspace-skill layer, with an explicit precedence and migration rule.

Settings surface (16 logical page IDs + searchable navigator): General, Appearance, App, AI, Input, Shortcuts, Memory, MCP Servers, Hooks, Extensions, Permissions, Labels, Messaging, Server, Workspace, and Preferences. QwenSettingsPage backs General/MCP/Hooks/Extensions; it is not an additional route. Hidden and feature-flagged pages still need explicit parity decisions.

Pages: ChatPage, DraftChatPage, PreferencesPage, ShortcutsPage, SkillInfoPage, SourceInfoPage.

Feature domains (per apps/electron/resources/docs/): automations, browser-tools, data-tables, html-preview, image-preview, labels, llm-tool, mermaid, pdf-preview, permissions, skills, sources, statuses, themes, tool-icons.

Doc tools (Python, stack-independent — needs new sidecar packaging): pdf_tool, xlsx_tool, docx_tool, pptx_tool, img_tool, ical_tool, doc_diff, markitdown_cli.

Packages: messaging-gateway + messaging-whatsapp-worker (upstream has 10 channels but no WhatsApp — consider rebuilding against packages/channels/base plugin API and upstreaming), session-tools-core, session-mcp-server, apps/viewer (transcript sharing).

Recent UI work — 17 features shipped in the last ~30 commits, highest regression risk because it is newest and least documented. Against current Web Shell, raw-Markdown copy, jump-to-latest, and prompt history are reusable; thinking selection and reduced motion are partial; the other 12 are absent: starter prompt suggestions (#73), interface zoom ⌘+/⌘-/⌘0 (#69), increase contrast (#67), chat text size (#65), conversation width (#63), live word/char count (#61), shortcuts search (#59), command palette recents (#57), thinking-menu shortcut (#55), prompt-history recall (#53), composer expand/collapse (#49), jump-to-latest (#47), copy-as-Markdown (#71), reduce motion (#51), thinking-level picker (#45), command palette ⌘K (#42), settings navigator search (#40).

Cross-cutting: i18n catalogs + lint:i18n:parity tooling (OpenWork ships 7 locales; Web Shell currently has English and zh-CN), Sentry wiring, voice, network-proxy.ts (Electron session proxy API — no Tauri equivalent), pets registry.

Retired by design: apps/electron main/preload/renderer (~119k LOC), packages/ui (30k), packages/server-core (35k), most of packages/shared's agent loop (95k).


6. Risks

# Risk Severity Mitigation
1 Product-shape divergence. Web Shell is coding-tool shaped (GitBranchIndicator, GitModePopover, BranchPickerPopover, artifacts/, agents/); OpenWork is knowledge-work shaped (Sources, Skills, Labels, Memory, Messaging). Pressure to add if (product === …) into shared code. High Phase 3 seam before Phase 4
2 Browser panes may be unportable (§3). High Spike in Phase 0
3 Data/credential loss on upgrade. credentials.enc key derivation and incompatible session formats need fixture-based migration tests. High Phase 5; treat as release blocker
4 Updater cross-contamination. High (low likelihood, unrecoverable impact) Generated config + release assertion
4b Inherited upstream defaults. The fork carries qwen-code's endpoint and telemetry plumbing: dashscope.aliyuncs.com / -intl / -us, coding.dashscope.aliyuncs.com/v1, gateway.alibaba-inc.com/dashscope/v1, a CLEARCUT path, and privacy.usageStatisticsEnabled handling. Some ModelStudio/DashScope routes may be intentional for OpenWork; the risk is shipping any endpoint, telemetry, auth, or privacy default without explicit ownership and disclosure. High Full audit in Phase 2; release assertion against an approved endpoint/telemetry allowlist
4c Moving parity target (§3). Feature work continuing on the Electron app during migration grows the Phase 4 backlog continuously. High Freeze policy decided before Phase 4
5 Toolchain collision. OpenWork is bun; qwen-code is npm, and prepare-runtime.js hard-requires it (npm_execpath is unavailable. Run through npm.). Medium Decide convergence explicitly
6 Engine differences. WebView2 / WebKitGTK vs bundled Chromium. Web Shell leans on Shiki, KaTeX, mermaid, echarts, CodeMirror, and shadowDom.ts. Medium Budget Linux QA or scope out of v1
7 Release-train coupling. Web Shell is versioned in lockstep with the monorepo (0.21.6). Medium Document branching/cherry-pick policy
8 Merge debt accumulation. Upstream ships ~2 minors/month; conflict cost scales worse than linearly with drift. Medium Monthly cadence, never skip
9 Attribution. Craft-derived code moving between trees carries Apache-2.0 notice obligations; Craft ships TRADEMARK.md. Low Legal pass in Phase 1
10 Perf/size expectations set too high. Low Measure in Phase 0 before committing publicly

7. Areas requiring special attention

  • Never reformat or reorganize upstream files. A single prettier run across packages/web-shell would poison every future merge.
  • Additive files never conflict. Prefer new files over in-place edits; when editing upstream files, insert a call into our module rather than inlining logic.
  • Upstream everything generic. Since the same team maintains both sides, a fix landed upstream permanently leaves our patch set — the single most effective conflict reducer available.
  • The 95 renderer files touching window.electron are the concrete Electron-coupling inventory; web-api.ts (277 lines) and the preload (421 lines) define the contract to re-implement.
  • Web Shell is 182,393 LOC — larger than OpenWork's current renderer (103,203). Porting to it is the bigger codebase absorbing the smaller.
  • Audit every inherited default, not just visible branding. Model/API endpoints, auth flows, telemetry targets, crash reporting, update endpoints, and analytics all arrive preconfigured for Qwen Code. Branding is what you see; endpoints are what ships. Treat this as a checklist with an automated assertion, not a review pass.
  • Security posture is inherited too. The daemon binds loopback with a per-launch bearer token, and Web Shell receives that token via URL fragment (#token=, never sent to the server). tauri.conf.json ships a restrictive CSP. Any OpenWork addition that widens the network surface — notably the messaging gateways and the WhatsApp worker — must be reviewed against that model rather than assuming it still holds.
  • Crash reporting needs rebuilding, not porting. @sentry/electron has no meaning post-migration; only @sentry/react carries over, and main-process crash capture needs a Tauri-native equivalent.

8. Upstream synchronization strategy

QwenLM/qwen-code  main
       │ fetch (never edit)
       ▼
vendor/upstream        pristine mirror branch
       │ merge at release tags only
       ▼
main                   OpenWork product branch
git remote add upstream https://github.com/QwenLM/qwen-code
git fetch upstream --tags
git checkout -b vendor/upstream upstream/main

# each sync:
git checkout vendor/upstream && git merge --ff-only v0.22.0
git checkout main && git merge vendor/upstream
npm install && git add package-lock.json
  • The pristine branch provides a stable three-way merge base and separates "what changed upstream" from "what we changed" — the question actually asked during conflict resolution.
  • Merge release tags, not main. Bounded, tested diffs.
  • Monthly cadence. Three minors behind costs far more than three times one minor.
  • PATCHES.md ledger so that, months later, a resolver knows whether a divergent line was deliberate.

9. Validation & acceptance criteria

Feature parity (blocking):

  • Parity matrix complete: every item in §5 marked ported / rebuilt / consciously dropped, with sign-off on each drop.
  • All 16 logical settings pages and searchable navigation reachable with equivalent function.
  • OpenWork-owned overlay in §5 verified: branding/distribution, all 3 curated marketplace entries, agent/product behavior, repository skills, and skill/agent storage.
  • All 17 recent UI features (§5) verified by hand — newest code, weakest coverage.
  • Doc tools pass existing smoke suites (test:doc-tools).
  • i18n parity lint passes across merged catalogs; no untranslated regressions.

Data integrity (blocking):

  • Upgrade from latest Electron build preserves settings, session history, and credentials with zero re-authentication.
  • Rollback path validated.

Release safety (blocking):

  • Automated assertion: shipped identifier + updater endpoint are OpenWork's, on every platform artifact.
  • Automated assertion: only explicitly approved and disclosed OpenWork/ModelStudio endpoints are reachable by default; no unintended upstream telemetry, CLEARCUT, updater, or auth endpoint ships; telemetry and usage-statistics defaults match OpenWork's stated privacy policy.
  • Crash reporting verified end-to-end from both the Rust shell and the web layer.
  • Signing and notarization green on macOS and Windows.

Platform:

  • macOS, Windows verified. Linux verified or explicitly descoped with a written decision.

Performance (measured, not assumed):

  • Bundle size and cold-start vs current Electron build, recorded before/after.

Sync process:

  • One full practice merge from an upstream release tag completed, conflicts resolved, time recorded as the cadence baseline.

10. Sub-issue breakdown

  1. Runtime bump 0.15.110.21.6 + ACP validation (Phase 0, independent value)
  2. Browser-pane / CDP portability spike (Phase 0, potential blocker)
  3. Browser-context audit via server:prod (Phase 0)
  4. Baseline bundle/perf measurement (Phase 0)
  5. Repo foundation + CI neutralization (Phase 1)
  6. Shell fork, branding, updater safety (Phase 2)
  7. Web Shell variant seam (Phase 3 — gates Phase 4)
  8. Feature port: settings surface (Phase 4)
  9. Feature port: Sources / Skills / Labels / Memory (Phase 4)
  10. Feature port: doc tools + sidecar packaging (Phase 4)
  11. Feature port: messaging + WhatsApp as channel plugin (Phase 4)
  12. Data migration: settings, sessions, credentials (Phase 5)
  13. Inherited-defaults audit: endpoints, telemetry, auth, crash reporting (Phase 2, release blocker)
  14. Platform QA + release pipeline (Phase 6)
  15. OpenWork-owned overlay: curated marketplace, agent/product behavior, repository skills, and skill/agent storage (Phases 2–5, release blocker)

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia con la checklist della Fase 0 e ispeziona apps/electron/src/main/browser-cdp.ts, browser-pane-manager.ts, packages/shared/src/agent/browser-tools.ts e scripts/vendor-qwen-code.ts. Esegui bun run server:prod e compila desktop-shell senza modifiche per stabilire l’accoppiamento con Electron e la baseline della piattaforma. Per considerare il lavoro completato, è necessario risolvere le domande architetturali elencate e suddividere la migrazione in sotto-issue circoscritte.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
electron, github-actions, node.js, python, rust, typescript
Ambito
ai, build-system, desktop, devtools, release
Tipo di issue
Funzionalità
Difficoltà
5/5
Tempo stimato
Più di una settimana
Stato di attività
Tranquilla
Chiarezza
Da chiarire
Idoneità per principianti
15/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.