Working on Fusion from inside a machine that already runs one, a plain
`pnpm dev` shares that instance's LIVE database. Everything durable hangs off
$HOME/.fusion — settings, credentials, central DB, the embedded Postgres data
dir — and a process pointed at a data dir whose postmaster is already running
attaches to it instead of starting its own.
--isolated spawns the dev child with HOME pointed at a sandbox, so it gets its
own settings, credentials and Postgres cluster on its own port. It also moves
the child's cwd, which is the half that is easy to miss: `fn dashboard`
derives its project from the working directory and has no project flag, so
isolating HOME alone leaves both instances on `<repo>/.fusion` — including
`.fusion/tasks/<id>/`, which the orphaned-task-dir sweep re-imports, so a
fresh dev database would adopt the real instance's tasks.
The sandbox defaults to ~/.fusion-dev/<checkout-name>/{home,project}: outside
the work tree so it neither shows up in git status nor dies on a clean
checkout, and keyed by checkout so two clones cannot collide. The project dir
is git init-ed on first use because Fusion projects are git work trees.
Changing cwd is safe because PRELOAD/LOADER/ENTRY are already absolute.
Verified in a container beside a running Fusion: the isolated instance
reported zero projects while the real one reported two, on separate Postgres
clusters (ports 42617 and 38311).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
When the dev child had not reported a bound port within 60s, the wrapper fell
back to the configured port and published a tunnel to it. In the case the
port fix exists for — a container whose own Fusion owns 4040 — that hands out
a dev-looking URL serving a completely different instance, with only a
passing "which may not be it" warning to show for it.
Observed with a dev server stopped on the interactive `Run central db now?
(Y/n)` prompt: it never listens, so it never reports, so the tunnel published
the container's Fusion instead.
A missing tunnel is a visible problem that explains itself; a tunnel to the
wrong app is a silent one. The wrapper now waits, unbounded, printing a
notice once a minute that names the interactive-prompt case. An explicit
--tunnel=PORT still publishes immediately, since it names a target the dev
child knows nothing about.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`pnpm dev --tunnel` published a bare URL under a "public, unauthenticated"
header. That label was wrong for the flag's own default target: --tunnel with
no port aims at the dashboard, which is bearer-token gated, so the recipient
of a shared link got a 401 with no token to supply.
resolveDevTunnelAuth() now classifies the target and the banner says what is
actually true of it:
token dashboard with auth on — prints the token and a ?token= link,
resolved from FUSION_DASHBOARD_TOKEN, FUSION_DAEMON_TOKEN,
then ~/.fusion/settings.json
token-pending first run, token not minted yet — defers to the dashboard's
own startup banner
no-auth --no-auth is on; the dashboard really is open
foreign a non-dashboard port; Fusion has no auth to lend it, the only
genuinely ungated case
Auth resolves at banner time rather than flag-parse time so a token the dev
child mints on a first authenticated run is already readable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Operator case: someone works inside a remote Fusion (a container, a shared box),
starts a dev server there, and needs to view it from their own browser. The dev
server binds inside that machine, so without a tunnel the only options are port
publishing or a VPN — both needing cooperation from whoever owns the host.
pnpm dev --tunnel # tunnels the dashboard port (PORT, default 4040)
pnpm dev --tunnel=5173 # tunnels a Vite dev server instead
pnpm dev --tunnel dashboard # tunnel the default port AND run the dashboard
FUSION_DEV_TUNNEL=1 pnpm dev
Cloudflare QUICK tunnels are usable here precisely because a dev server is HTTP:
no account, no domain, no card. The TCP endpoints that SSH would have needed
require a card (ngrok) or a domain plus Zero Trust (Cloudflare) — that asymmetry
is why this exists for HTTP only, and it is recorded in the module header so the
next person does not retry the SSH variant.
Design decisions:
- Tunnel failure is NON-FATAL. A missing cloudflared or a tunnel that never
publishes a URL logs and is skipped; losing a preview URL must never cost the
operator their dev loop.
- Watch-mode restarts reuse the existing tunnel. A fresh quick tunnel hands out a
different hostname each time, which would invalidate an already-shared link.
- `--tunnel` consumes a following token only when it is numeric, so
`--tunnel dashboard` forwards `dashboard` to the dev command rather than
tunnelling port NaN. That is the bug this flag shape invites, so it is tested.
Verified end to end in a container: a dev server bound to 127.0.0.1 inside it was
fetched from the public internet through the tunnel (200, correct body). Also
confirmed that tunnelling the DASHBOARD port does not weaken auth — unauthenticated
requests through the tunnel return 401 for /api/tasks, /api/settings and
/api/artifacts, with only /api/health open by design.
Adding two fields to parseDevWrapperArgs' return broke two existing strict toEqual
assertions; those were updated rather than loosened to toMatchObject. 27 tests pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
## Summary
Add an opt-in source-development loop that restarts the dashboard and
engine when runtime TypeScript or JSON changes. Use `pnpm dev:watch`;
`pnpm dev:hmr` now combines Vite UI HMR with the same supervised
API/engine restart path.
The watcher filters tests, fixtures, generated declarations, build
output, and task state. It coalesces bursts with a two-second maximum
wait, waits for the child to acknowledge its IPC listener, and rebuilds
runtime dist artifacts before a source-triggered respawn.
## Safety model
- Close scheduler, triage, heartbeat, mission, routine, self-healing,
and merge admission before checking for active work.
- Let already-running agents reach a safe boundary; do not mutate
durable pause settings.
- Enter the existing graceful exit-code-86 shutdown and supervised
respawn path.
- Retry failed liveness reads and declined restart requests instead of
dropping the pending change.
- Keep ordinary `pnpm dev` behavior unchanged; inherited watch state
does not break nested non-dashboard development commands.
A development restart intentionally replaces the dashboard process, so
transient dashboard connections and project dev-server children
reconnect or restart with it. Agent work is the protected boundary.
## Validation
- `pnpm lint`
- `pnpm test:gate` (753 tests passed across engine, core, PostgreSQL
gate, and CI-shape suites)
- Focused CLI watcher/restart/supervision suites: 40 tests passed
- Focused engine drain/manager suites: 52 tests passed
- `pnpm --filter @runfusion/fusion typecheck`
- `pnpm --filter @fusion/engine typecheck`
- `pnpm verify:fast` (13 steps passed, including CLI build and real
health boot smoke)
- Manual unsupported-command probe confirms explicit `--watch` fails
clearly outside the dashboard command
## Post-Deploy Monitoring & Validation
- Watch for `[fusion:dev] source changed`, `source restart deferred`,
`active work drained`, and `restart requested` logs during the first
watched development session.
- Healthy behavior is one exit-86 respawn per edit batch, no interrupted
active agents, refreshed dist artifacts, and a healthy dashboard after
respawn.
- Investigate repeated restart loops, watcher attachment warnings,
declined restart retries, or liveness-read failures.
- Immediate mitigation is to use ordinary `pnpm dev` without `--watch`;
no production runtime behavior or durable setting needs rollback.
- Validation owner: Fusion maintainers during the first source edit
after merge.
---
[](https://github.com/EveryInc/compound-engineering-plugin)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added `pnpm dev:watch` to automatically restart development runtime
processes when source files change.
* Development restarts now wait for active work to finish, preventing
new work from starting during the transition.
* Enhanced `pnpm dev:hmr` with graceful runtime source restarts while
keeping the dashboard available.
* Rapid source changes are grouped to avoid unnecessary restarts.
* **Documentation**
* Updated development setup and contribution guides with the new watch
workflow.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Update AGENTS.md, RELEASING.md, contributing.md with the structured
changeset format guide. Add .changeset/README.md template. Add changeset
for this change. Update distill-release-notes.mjs with final version.
Expose the docs README index suite as a focused CLI test lane and document its deterministic invocation.
- Add a package script for running only the docs README index Vitest file.
- Lock the package-config contract around the new script and dashboard quality runner expectations.
- Clarify the CI shard docs to pass Vitest shard flags without a bare separator.
Files changed:
docs/contributing.md | 2 +-
packages/cli/package.json | 1 +
packages/cli/src/__tests__/package-config.test.ts | 37 ++++++++++++++++++-----
3 files changed, 31 insertions(+), 9 deletions(-)
Fusion-Task-Id: FN-6355
Fusion-Task-Lineage: 2a02bc5f-2407-4bad-8aed-afa519826ce7
Document the repository-local Beads issue workflow for contributors.
- Add the bd ready/claim/create/close/sync workflow with expected outcomes.
- Document Beads issue types and priority levels.
- Clarify that local Beads tracking is separate from the Fusion storage evaluation.
Files changed:
docs/contributing.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
Fusion-Task-Id: FN-6330
Fusion-Task-Lineage: 9a56def0-40bf-4e61-8582-4bb66e382a3a
- pr-checks.yml: gate job = boot smoke + pnpm test:gate; shards/slow/inventory removed
- full-suite.yml (new): 4-way shards, engine slow tier, inventory guard on push to main
- ci.yml deleted (trigger-disabled since FN-1541; was dead config)
- ci-workflow.test.ts rewritten to pin the new gate shape; release/signing blocks preserved
- docs/contributing.md: pnpm test:gate is the merge gate; verify:workspace repositioned as deep opt-in
BRANCH-PROTECTION CUTOVER: set required checks to exactly [Lint, Typecheck, Build, Gate] after merging; open PRs must rebase.
Fill zh-CN, zh-TW, fr, and es catalogs for the migrated keys. zh-CN and zh-TW
are independently localized (Simplified vs Traditional script + Taiwan
vocabulary, e.g. 项目/任务 vs 專案/工作), not script-converted. Translations are
machine-drafted and flagged for human review in locales/TRANSLATION_STATUS.md.
Add docs/i18n-contributing.md (translate / add-a-language / --lang usage) and
cross-link it from contributing.md and cli-reference.md. i18n:status reports
100% for all four locales across the migrated key set.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Document and enforce pnpm build-script review decisions to prevent ignored-script install warnings.
- add reviewed ignoredBuiltDependencies entries to the root pnpm config and mirror the effective policy in pnpm-workspace.yaml
- add a regression test that verifies reviewed dependencies are categorized exactly once and stay aligned across both config files
- document the pnpm build-script approval policy in contributing docs and link plugin authoring guidance from AGENTS.md and PLUGIN_AUTHORING.md
Files changed:
AGENTS.md | 5 ++
docs/PLUGIN_AUTHORING.md | 3 +-
docs/contributing.md | 14 ++++
package.json | 9 +++
pnpm-workspace.yaml | 14 ++++
scripts/__tests__/pnpm-build-scripts-config.test.mjs | 74 ++++++++++++++++++++++
6 files changed, 118 insertions(+), 1 deletion(-)
Fusion-Task-Id: FN-5927
Fusion-Task-Lineage: 192bbed9-c5ed-45cb-b4bd-fb18514e2783
Implements weighted shard planning for the CI test sharding script, with deterministic test coverage and documentation updates to `contributing.md`.
Fusion-Task-Id: FN-4043
- Create a disposable HOME/USERPROFILE env for scripts/test-changed.mjs execution
- Run isolation guard checks with the same isolated env, including cache-hit no-op paths
- Clean up temp HOME after test execution to avoid residue
- Update test coverage and contributing docs for the shared isolation behavior
Fusion-Task-Id: FN-3610
- Expand test-changed coverage and shard selection assertions for CI workflows
- Improve vitest worker temp-directory utilities and related core/CLI tests
- Refine test isolation guardrails and runtime ignore handling for live .fusion noise
- Update contributing guidance and root test script usage for the verified workflow
Fusion-Task-Id: FN-3607
This merge lands five FN-3593 commits establishing a test isolation contract with a new `scripts/check-test-isolation.mjs` guard that scans for accidental `beforeEach`/`afterEach`/`beforeAll`/`afterAll` in setup helpers, plus per-package `setup-test-isolation.ts` bootstraps that canonicalize the pat
Fusion-Task-Id: FN-3593
Merges FN-3470 in two steps: first, runtime plugins now prefer source path aliases over build artifacts, with hardening tests for vitest alias resolution and plugin view registry updates; second, a new `ensure-test-artifacts.mjs` bootstrap script guarantees required test files exist before test runs
Fusion-Task-Id: FN-3470
This merge refactors the test-changed script and adds new CLI tests (FN-3234), keeping automation on the full-suite path. It includes a new test file for the root test command, updates to the CI workflow, and documentation improvements.
Fusion-Task-Id: FN-3234
- pnpm build now excludes @fusion/desktop and @fusion/mobile by default
(recursive build still available as pnpm build:all). Saves time on
workspace-wide builds that don't need the native shells.
- Hoist the per-package max-worker computation into a shared
packages/core/src/__test-utils__/vitest-workers.ts util. Every
vitest.config.ts now calls computeMaxWorkers(), which honors
VITEST_MAX_WORKERS, FUSION_TEST_TOTAL_WORKERS, and a per-config
defaultCap, clamped to cpus-1.
- pnpm test sets VITEST_MAX_WORKERS=2 so the workspace run keeps total
fan-out modest with --workspace-concurrency=2.
- Switch dashboard vitest pool from forks to threads so jsdom/React
suites share a V8 heap instead of duplicating ~500MB per worker.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This merge lands ListView UX improvements and fixes (split-pane behavior, visual refinements), adds a runs tab to the AgentDetailView, stabilizes extension integration tests, and updates contributing docs. Test coverage expanded significantly with new assertions for ListView and TaskDetailModal.
Fusion-Task-Id: FN-3204
Merges FN-3183/FN-3186 (priority picker in quick-entry box) and FN-3189 (CLI slow-lane test gating and CI lane) into the codebase. The quick-entry box gains inline priority selection, while the test suite introduces explicit slow/pre-release lane classification and a corresponding CI gate in the wor
Fusion-Task-Id: FN-3189
This merge brings three major changes: a `/clear` command for Chat and QuickChat with a fixed session notification banner, a complete overhaul of the Todo item row structure and styling with mobile-responsive CSS tests and documentation of the action row pattern, and a significant expansion of droid
Fusion-Task-Id: FN-3063
Published a canonical SSE architecture reference, with a major rewrite of the real-time dashboard documentation and a new contributing guideline for SSE patterns (FN-3054).
Fusion-Task-Id: FN-3054
Replace the legacy ANSI-based DashboardTUI with an Ink/React rewrite
under packages/cli/src/commands/dashboard-tui/, delete the standalone
@fusion/tui package, and make `fn` (no args) launch the dashboard.
The new TUI keeps the existing 5-panel status mode (system, logs,
utilities, stats, settings) but adds an interactive mode (b/a/g) with
three views: a kanban board with project picker and per-task detail,
an agents list+detail with state management, and a settings editor.
Bordered focus-aware panels, solid-background help overlay, static
all-blue FUSION splash that adapts to small terminals. DashboardTUI
and DashboardLogSink public API are unchanged so dashboard.ts only
needed import-path updates plus interactiveData/loadingStatus wiring.
Also adds zod to @fusion/dashboard to satisfy a peer dep introduced
by pi-coding-agent 0.70.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Assert contributing docs explicitly state that pnpm test must run without prior build outputs
- Add CI workflow test coverage to keep docs and verify:workspace ordering aligned
- Expand Vitest workspace alias assertions to include @fusion/test-utils and src-only replacements
- Validate real symbol imports from workspace packages when dist directories are absent
- Add root verify:workspace script enforcing lint -> test -> build order
- Update CI workflow to run verify:workspace as the single workspace gate before binary packaging
- Add CLI guardrail tests for workflow sequencing and root script contract invariants
- Document deterministic workspace bootstrap expectations in contributing guide
- Clarify bundle-output test bootstrap intent for explicit artifact setup
Move the publishable CLI under the new @runfusion npm org for the first
public release. Reset version to 0.0.1 since the previous name was never
actually published. Rewrite packages/cli/README.md (the npm page) to
mirror the root README marketing — Fusion logo, reel GIFs pulled from
raw.githubusercontent.com, feature grid, tagline — and fix the stale
dustinbyrne/kb image link and ISC-vs-MIT license mismatch. Propagates
the name through root scripts, RELEASING.md, workflows, and docs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Update memory docs and contracts to reference canonical .fusion/memory files while treating the legacy top-level memory file as compatibility-only
- Tighten memory backend path normalization messaging and map stale qmd legacy top-level memory results back to .fusion/memory/MEMORY.md
- Remove legacy memory read/write fallback branches from backend initialization paths and rely on ensureOpenClawMemoryFiles() migration behavior
- Preserve migration-seeded legacy content during ensureMemoryFile() bootstrap and add regression coverage for seeded long-term memory creation
- Update memory architecture and contributing docs to describe .fusion/memory/ as the canonical layered workspace
- Reframe .fusion/memory.md references as a deprecated legacy fallback used only for migration/alias compatibility
- Expand the memory plugin contract with explicit layered layout, migration behavior, and invariant language
- Align settings reference memory-insight file descriptions with the canonical long-term memory model
- Rewrite memory backend contract docs to match shipped MemoryBackend interfaces, capabilities, and registry behavior
- Clarify .fusion/memory/ as the canonical layered workspace and keep .fusion/memory.md compatibility-only
- Document backend resolution through memoryBackendType with qmd as the default and qmd-to-file search fallback behavior
- Synchronize architecture, contributing, and settings reference docs with the updated memory model terminology
- Remove legacy .fusion/memory.md fallback references and normalize prompts/docs to .fusion/memory/MEMORY.md
- Stop legacy mirror writes and fallback reads in core memory backend and project memory flows
- Update engine worktree boundary checks and tests for canonical memory file handling
- Align dashboard memory/settings surfaces and route tests with canonical memory behavior
- Add model-favorites persistence test coverage for mission interview and new agent dialogs
- Update core and engine prompt text to reference .fusion/memory/ with MEMORY.md and daily-note guidance
- Allow worktree tool boundary access to .fusion/memory/ files while preserving legacy .fusion/memory.md compatibility
- Revise memory compaction/insight extraction messaging and related type/docs comments to use canonical memory paths
- Refresh dashboard and test expectations across core/engine/dashboard/docs for the new memory path wording