Adopt AGPL-3.0-only for the Community Edition, reserve separate commercial licensing, and set the permanent macOS Bundle ID to com.rydersun.meldwork. Add fail-closed Developer ID/notarization preflight and post-sign checks, package license notices, and refresh public MVP, signing, architecture, security, and verification documentation. Checks: frontend 237/237; desktop 842/842; web and desktop builds; production audits; pack and DMG/ZIP dist; strict codesign; clean-profile packaged startup; archive Bundle ID/license inspection; Markdown links; git diff --check.
17 KiB
Architecture
Product Boundary
Meldwork is a local Electron desktop product for direct and multi-Agent work with explicitly selected Skill, image, and knowledge-source context. It has no account system, tenant model, required application server, remote conversation store, email delivery, scheduled jobs, or public SEO surface. Optional Agent, Cloud, and Channel Connectors run behind the Electron main-process trust boundary and are disabled until explicitly configured.
The supported product surface is the packaged Electron application. The frontend is a renderer bundle; without the local preload bridge it shows a desktop-required state and cannot operate the workspace.
Components
| Component | Responsibility | Primary evidence |
|---|---|---|
| Vue renderer | Agent-first multi-session UI, direct-session rename/delete, live direct-chat conclusions and inline execution summaries, group-chat result streaming with an expandable per-Agent/right-side trace panel, per-round navigation, background completion markers, first-run carousel, conversation/Skill/image/knowledge composer UI, bounded attachment-preview cache, theme/i18n, user confirmation and input collection | frontend/src/App.vue, frontend/src/components/RunTracePanel.vue, frontend/src/composables/useAttachmentPreviews.js, frontend/src/desktop.js, frontend/src/knowledgeBaseCatalog.js |
| Electron preload | Exposes narrow workspace, Human Gate, Cloud control, installer/Skill, attachment, Provider, and knowledge-source methods through window.roundrelayDesktop only to a local file: document; Channel ingress has no renderer API |
desktop/src/preload.cjs |
| Electron main | Trust boundary for IPC authorization and shutdown gating, persistence, attachment import/preview, Connector registration, Skill and knowledge-source validation, local/Cloud execution, Channel receivers, navigation, sanitized run events, operating-system notifications, Provider storage, and installer control | desktop/src/main.cjs |
| Local workspace | Persists Meldwork conversations, final replies, compact evidence capsules, safe message metadata, task-scoped group Sessions, conversation-scoped direct Sessions, legacy Session migration, Agent-specific transcript deltas, Agent preferences/runtime evidence, and active run coordination | desktop/src/local-workspace.cjs |
| Run Ledger | Atomically checkpoints bounded, sanitized per-run and per-Agent state for stop/crash recovery, marks nonterminal runs and Agent attempts interrupted after restart, supports idempotent reconciliation of missing terminal Agent messages, and purges records with their conversation | desktop/src/run-ledger.cjs |
| Context Pack and delivery stores | Capture immutable, content-addressed Task inputs, attempt-specific approved prompts, exact outbound fingerprints, source hashes, target scope, and native Session provenance | desktop/src/context-pack-store.cjs, desktop/src/local-workspace-context-packs.cjs |
| Outcome store | Persists typed Artifacts, Evidence, Findings, and Adoption records separately from diagnostic reasoning and tool summaries | desktop/src/outcome-store.cjs, desktop/src/outcome-records.cjs |
| Human Gate store | Persists permission, budget, and decision requests and their terminal user/system decisions without exposing raw request payloads to the renderer | desktop/src/human-gate-store.cjs, desktop/src/human-gate-coordinator.cjs |
| Scheduling and failure policy | Enforces run budgets, retry policy, per-Agent controls, and global/workspace scheduling | desktop/src/run-scheduler.cjs, desktop/src/failure-policy.cjs |
| Agent Connector registry/runtime | Validates approved manifests and instances, separates CredentialRefs, records Connector/upstream versions, and reduces versioned idempotent Run Events | desktop/src/agent-connector-manifest.cjs, desktop/src/agent-connector-registry.cjs, desktop/src/agent-connector-runtime.cjs |
| Attachment store | Imports validated local images, media, documents, code/configuration files, Office files, and archives into private app-owned storage, verifies metadata/checksums on read, and removes unreferenced entries | desktop/src/attachment-store.cjs, desktop/src/image-dimensions.cjs |
| Local Skill catalog | Scans bounded known roots per Agent and returns sanitized Skill coordinates without exposing paths or contents | desktop/src/local-skill-catalog.cjs |
| Local knowledge-source catalog | Detects and probes code-defined Feishu, DingTalk, and Obsidian access modes, returns sanitized readiness, validates task selections, and exposes reference-only future sources | desktop/src/local-knowledge-base.cjs |
| Knowledge Connector runtime | Executes main-owned bounded search/fetch/snapshot/citation operations for explicit source selections; the renderer receives only sanitized discovery and selection records | desktop/src/local-knowledge-connectors.cjs, desktop/src/knowledge-connector-filesystem.cjs |
| Cloud Agent runtime | Persists remote job/cursor state and idempotent input, permission, cancel, callback, polling, reconciliation, and Artifact operations without requiring a server | desktop/src/cloud-agent-runtime.cjs, desktop/src/cloud-agent-operation-store.cjs |
| Channel ingress runtime | Verifies main-owned Connector events, rejects replay/expired delivery, maps external actors and subscriptions to local Tasks, queues a durable Inbox, and audits outbound replies | desktop/src/channel-ingress-runtime.cjs, desktop/src/channel-inbox-store.cjs |
| Knowledge-source store | Persists only the user-selected Obsidian Vault path; Feishu and DingTalk credentials remain owned by their local CLIs | desktop/src/knowledge-base-store.cjs |
| CLI adapters | Detect and invoke supported local Agent executables with per-Agent arguments and constrained child environments | desktop/src/cli-adapters.cjs |
| Agent installer | Detects Agents and runs allowlisted npm packages or official installer scripts after user confirmation | desktop/src/agent-installer.cjs |
| Provider store | Validates Provider metadata and encrypts the API key with Electron safeStorage |
desktop/src/provider-store.cjs |
| Managed OpenClaw runtime | Creates isolated local configuration and a restricted tool policy for OpenClaw | desktop/src/openclaw-runtime.cjs |
Trust Boundaries
- The renderer is not trusted with Node.js, Agent executable paths, native Agent session IDs or storage paths, attachment paths, Skill paths/contents, raw Provider credentials after saving, arbitrary filesystem reads, or arbitrary process execution. User-selected conversation workdirs and the user-selected Obsidian Vault path are intentional UI-visible paths; pasted image bytes use one exact import payload.
- Preload exposes only named IPC methods. Main validates that every request comes from the current main frame and exact bundled frontend file.
- Main owns local files, OS dialogs, attachment validation/storage, Skill and knowledge-source discovery/revalidation, Connector approval/registration, Agent discovery, child processes, Cloud observation, Channel authentication, installer downloads, and credential encryption.
- Agent CLIs are external processes. They receive a selected working directory, a constrained environment, permission flags, main-resolved image paths, target-scoped immutable Skill snapshots, and validated knowledge snapshots or read-only hints after capability checks.
- Provider, Agent Connector, Cloud Connector, Channel Connector, and installer destinations are external trust boundaries. Provider URLs are user supplied and validated; manifests and Connector instances fail closed unless explicitly approved; Channel signatures and Workspace scope are verified before Task delivery.
- Harness events expose only allowlisted status, conclusion deltas, reasoning summaries, plans, tool lifecycle summaries, bounded result metadata, and source message IDs. Raw chain-of-thought, commands, executable paths, native session references, credentials, unrestricted stdout/stderr, and arbitrary tool payloads remain outside the renderer and shared Agent context.
Local Data
| Data | Location | Protection |
|---|---|---|
| Meldwork conversations, messages, native session-reference mappings, Agent preferences/runtime evidence | Electron user data: roundrelay-workspace.json |
Local JSON written through main; group native references are keyed by Task and Agent, direct references by conversation and Agent, all remain main-only, and snapshots remove executable paths |
| Bounded run checkpoints | Electron user data: roundrelay-run-ledger.json |
Atomic private writes; 0600 file, with new parent directories created as 0700; at most 64 sanitized runs with bounded Agent output/events/source IDs; no raw commands, paths, credentials, or native session references |
| Immutable Context Packs, delivery records, content blobs, typed outcomes, and Human Gates | Electron user data under roundrelay-private/ |
Content-addressed or atomically written main-only records; renderer snapshots expose only bounded IDs, provenance summaries, budgets, and pending Gate choices |
| Cloud operations and Channel Inbox | Electron user data under roundrelay-private/ |
Private 0600 stores keep opaque remote references, idempotency state, signed-event-derived Task data, delivery cursors, Task mappings, and outbound audit records; raw signatures, headers, credentials, and complete IM history are not exposed to the renderer |
| Imported attachments | Electron user data under attachments/ |
App-owned copy; 0700 directories, 0600 files, type/MIME/size validation, image-dimension checks where applicable, metadata checksum, ID-only renderer access |
| Provider metadata and encrypted key | Electron user data: roundrelay-provider.json |
API key encrypted with safeStorage; file written atomically with mode 0600 |
| Knowledge-source preference | Electron user data: roundrelay-knowledge-base.json |
Stores the selected absolute Obsidian Vault path only; written atomically as a private file |
| Managed OpenClaw state/config | Electron user data under openclaw-managed/ |
Per-scope directories, mode 0700; config mode 0600; API key passed by child environment |
| Theme, locale, and onboarding completion | Renderer localStorage |
Non-secret UI preferences |
Live renderer events remain transient. Main separately checkpoints a bounded sanitized run snapshot, while final replies and compact evidence capsules are stored with local conversation messages so a group result can reopen its trace without retaining raw tool output. A conclusion already emitted through answer deltas is retained in the terminal failure, timeout, stop, or interruption message. On restart, nonterminal checkpoints become interrupted, then every recoverable terminal Agent checkpoint that is not already represented in the conversation is materialized with its recorded status and output. Completed and partial attempts become Agent messages; failed, timed-out, stopped, and interrupted attempts become status-specific system messages. If a matching agentRunId message already exists but lacks its Ledger output, reconciliation enriches it once. Writable Agents are never auto-resumed. Persisted attachment references contain safe metadata only, and Skill references contain sanitized target/namespace/slug/name coordinates. Renaming a conversation preserves its native sessions; changing its working directory clears them to prevent cross-workspace resume. Deleting a Meldwork conversation must first remove its Run Ledger records, then remove its app-owned messages, native session-reference mapping, and attachments no longer referenced elsewhere. It does not call a CLI-specific deletion command or remove history stored by Codex, Hermes, or another Agent CLI.
There is no Meldwork-hosted remote data store or application account namespace. Managed OpenClaw paths are isolated by local conversation and working-directory scope inside Electron's per-user data directory. Optional Cloud jobs and Channel deliveries remain owned by their configured external systems while local recovery state stays in main-owned private stores.
Network Surface
- Agent CLIs may call their own configured model providers.
- Selected attachments and Skill-influenced prompts may be sent by an Agent CLI to its configured model provider after local validation and capability checks.
- Compatible Agents may receive the user-configured Provider URL/model/key from main.
- Feishu and DingTalk readiness probes may invoke their configured local CLIs; a selected Agent may then use those CLI connections with read-only instructions.
- An explicit Obsidian selection is searched and fetched through the main-owned read-only filesystem Connector, then captured as an immutable snapshot or explicit live reference before Agent invocation.
- Approved Agent Connectors may contact only their declared outbound destinations and receive main-owned CredentialRefs rather than renderer-provided secrets.
- Configured Cloud Connectors may submit and observe remote jobs, answer waiting input/permission, cancel idempotently, and fetch declared Artifacts.
- Configured Channel Connectors may keep a main-process receiver active while the UI window is closed; verified events become scoped Task requests and audited replies rather than copied chat history.
- The installer may download fixed Hermes/Kimi installer URLs or invoke npm for fixed package names.
- Credential-free HTTPS links may be opened in the operating-system browser; remote navigation is denied inside the Electron window.
- The renderer CSP uses
connect-src 'self'and does not directly call model or application APIs.
Known Risks And Assumptions
- Installer recipes use mutable upstream packages or scripts and currently do not verify a pinned digest or signature (
desktop/src/agent-installer.cjs). - Conversation history is local but not application-encrypted (
desktop/src/local-workspace.cjs). - Sanitized Run Ledger checkpoints are local and private but not application-encrypted. The store assumes one Electron main-process writer and recovers only the last persisted bounded checkpoint, not every in-memory event (
desktop/src/run-ledger.cjs). - Conversation deletion is privacy-first across two local JSON stores rather than transactional: Ledger records are removed first; if the workspace write then fails, in-memory conversation state is rolled back and remains retryable, but the deleted trace checkpoints are not recreated.
- Imported attachment copies are private and integrity-checked but not application-encrypted (
desktop/src/attachment-store.cjs). - Local Skill files are untrusted prompt input. Main prevents renderer-supplied paths and cross-Agent selection, but a selected Skill can still influence Agent behavior (
desktop/src/local-skill-catalog.cjs,desktop/src/local-workspace.cjs). - Obsidian selections use a main-owned read-only Connector with bounded retrieval, immutable snapshots, and citation hash verification. Generic Feishu and DingTalk access remains CLI-owned and prompt-mediated; their authentication and document permissions are not controlled by Meldwork. Notion, Confluence, Google Drive, and SharePoint are reference-only planned sources and are not active Connectors.
- Native image support is currently limited to Codex, Hermes, and OpenCode, with different per-run limits; mixed groups fail before execution when they cannot receive equal image context (
desktop/src/cli-adapters.cjs). - Read-only enforcement is owned by the Obsidian Connector for captured selections. Agent workspace and CLI-mediated remote access still depends partly on each upstream CLI honoring its permission flags; Meldwork adds per-CLI hardening where available (
desktop/src/cli-adapters.cjs). - Provider requests and native Agent authentication are external dependencies; Meldwork cannot guarantee their availability or data handling.
- Agent/Cloud/Channel Connector contracts validate provenance, scope, and idempotency, but the external implementation must honor its CredentialRef, outbound destination, cancellation, and signature-verification obligations. The production build registers no Cloud or Channel Connector by default.
- macOS packaging uses ad-hoc signing for local validation, not a notarized public release (
desktop/scripts/after-pack.cjs).
Capability Absences
- No email sending, so there is no
emails.md. - No cron or scheduled background work, so there is no
cron.md. - No supported public or indexable routes, so there is no
seo.md.