Imported from xuzhougeng/wisp-science (
AGENTS.md). Install upstream withnpx skills add xuzhougeng/wisp-science. Copyright stays with the author.
AGENTS.md
Project Orientation
wisp-science is a Rust/Tauri/Leptos local-first scientific computing agent. The long-term product direction is a research workbench: local, WSL, SSH servers, GPU hosts, schedulers, literature tools, runs, data assets, artifacts, papers, and decisions should be represented as one project-level control plane. The durable product nouns are Project, ExecutionContext, DataAsset, Run, Artifact, Paper, and Decision.
Do not implement broad product vision in one change. Prefer small PRs that add one durable abstraction, persistence table, tool, UI surface, or testable behavior at a time.
Repository Layout
crates/wisp-core/: agent loop, context management, memory, provenance helpers.crates/wisp-tools/: built-in tools such as read/write/edit/search/grep/shell.crates/wisp-store/: sqlx SQLite store. Migrations are incrates/wisp-store/migrations/0000_init.sql; idempotent migration code lives incrates/wisp-store/src/lib.rs.crates/wisp-runtime/: managed runtime support (currently the persistent Python REPL tool).crates/wisp-skills/: SKILL.md discovery and use_skill tool.crates/wisp-dto/: shared serde DTOs for the UI ⇄ Tauri invoke/event contract. Compiles for wasm32 and native; data only, no Leptos/Tauri deps.ui/src/dto.rsre-exports it, andsrc-tauri/src/dto_contract_tests.rsdeserializes backend payloads into these types to catch serde drift. Add new cross-boundary shapes here, not as hand-mirrored copies.crates/wisp-runs/: shared Run control plane (run_in_context,monitor_run, harvest/cleanup/transfer) used by the CLI and the desktop shell.crates/wisp-cli/: headlesswisp-sciencebinary (interactive,run,rpc,eval).src-tauri/: desktop shell, Tauri commands, app state, SSH host registry.src/app_state.rsownsAppState/SessionRuntime/ActiveProject;src/agent_turn.rsowns the send_message turn pipeline, turn queue, and stop_agent;lib.rskeeps command registration, setup, and shared helpers.src-tauri/src/model_catalog_shared.rs: distilled models.dev catalog types and exact-id lookup, compiled into bothbuild.rsand the runtime.build.rsfetcheshttps://models.dev/api.jsonat build time and falls back to the checked-insrc-tauri/model_catalog.snapshot.jsonwhen offline (WISP_CATALOG_OFFLINE=1skips the fetch); runscripts/refresh_model_catalog.shto refresh the snapshot before releases.ui/: Leptos frontend.ui-tests/: Playwright tests with mocked Tauri bridge.skills/: bundled scientific workflows.docs/superpowers/specs/anddocs/superpowers/plans/: architecture notes and implementation plans.
Engineering Rules
- Keep Windows and macOS behavior explicit. Avoid Unix-only assumptions unless gated behind an SSH/WSL context.
- Never require a real SSH host, GPU, SLURM cluster, WSL distro, API key, or network access in automated tests. Use pure parsing tests, fake command runners, temporary directories, and mocked Tauri commands.
- Store secrets in the existing keyring path, not SQLite. SSH private key contents must never be copied into SQLite.
- For long-running compute, do not extend the existing
shelltool timeout as the main solution. Add a structured run/job abstraction. - For large scientific data, do not default to local sync. Represent large data as remote references with checksums/metadata where possible.
- Keep schemas backward-compatible and migrations idempotent, following the existing
wisp-storestyle. - Model context/output ceilings come from the baked models.dev catalog via exact model-ID match (gateway
vendor/modelids match on the tail segment). Never reintroduce prefix or family matching — a family id must not absorb a longer sibling. - Do not refactor or split modules solely because a file is long. Require a concrete reason tied to the active change, such as mixed responsibilities causing repeated edits, a needed dependency or test boundary, or a measured maintenance problem, and stop once that problem is solved. Large composition/root modules are acceptable; do not pursue arbitrary line-count targets or speculative abstractions.
- Every dismissible overlay, dialog, menu, and popover must participate in a window-level Escape stack ordered from the visually topmost surface down. Root-owned state belongs in the app stack; component-local state may use a scoped window listener that is removed on cleanup. Do not rely on a DOM
keydownhandler receiving a bubbled event or onautofocus. A local handler is only appropriate when an inner state must consume Escape before its parent; it must prevent propagation. Tests must press Escape immediately after opening, without first moving focus inside, and verify that one press closes only the topmost layer while its parent remains open. - UI icons come from one shared set:
compose_icon()inui/src/app_support/messages.rs(Lucide-style 24×24 stroke SVGs,stroke="currentColor"). Never introduce icon fonts, emoji/unicode glyphs, or per-component CSS mask icons (the removed.gisystem); add a newcompose_iconkind instead. Give each action a distinct, semantically matching icon — do not reuse the same icon for two different entries in one menu. Size icons via a component-scopedsvgCSS selector, not by adding wrapper classes to the shared set. - Add or update tests with every behavior change.
- Update docs when user-visible behavior changes. Update release notes only when explicitly requested or when preparing a release (see Cutting a release).
- If
cargo fmt --all -- --checkfails because of formatting drift, runcargo fmt --alland keep formatting-only changes in a separate commit.
Verification Commands
Run the narrowest relevant checks first, then the full suite before declaring done:
cargo fmt --all -- --check
cargo test --workspace
For UI or Tauri command changes, also run:
cd ui && cargo check --target wasm32-unknown-unknown
cd ../ui-tests && npm ci && npx playwright test
For MCP-related changes, also run:
cargo run -p wisp-mcp --example smoke
Cutting a release
When asked to release, follow this section. Create the GitHub Release with gh before CI uploads installers, so platform jobs never write the title or notes.
-
Bump
workspace.package.versioninCargo.toml,ui/Cargo.toml, andsrc-tauri/tauri.conf.json. Update workspace package versions inCargo.lockandui/Cargo.lock(onlyname = "wisp-*"entries — do not bump third-party crates that happen to share the same version). -
Write bilingual notes at
.github/release-notes/vX.Y.Z.md. Put the GitHub title in an HTML comment on the first line:<!-- release-title: v1.6.0: Theme --> -
Commit as
Release vX.Y.Zand pushmain. Do not push a tag yet. -
Publish the release with
ghfrom that commit. This creates the tag and the notes in one step; the tag push then starts CI:TITLE="$(scripts/github_release_notes.sh .github/release-notes/vX.Y.Z.md vX.Y.Z | sed 's/^title=//')" gh release create vX.Y.Z \ --title "$TITLE" \ --notes-file .github/release-notes/vX.Y.Z.md \ --target "$(git rev-parse HEAD)"On Windows PowerShell:
$title = (bash scripts/github_release_notes.sh .github/release-notes/vX.Y.Z.md vX.Y.Z) -replace '^title=','' gh release create vX.Y.Z --title $title --notes-file .github/release-notes/vX.Y.Z.md --target (git rev-parse HEAD) -
Confirm the release exists, then wait until CI has started (Create Release, Windows Release, macOS Release, Linux Release):
gh release view vX.Y.Z gh run list --branch vX.Y.ZCreate Release is a no-op when the release already exists. Platform workflows attach installers only; they must not be given a release body. Only watch those runs to completion when the user asked to ship or verify the published assets.
Do not git push origin vX.Y.Z after gh release create — the tag already exists on GitHub. To fix notes on an existing release, edit the notes file and run the Create Release workflow with overwrite_notes, or gh release edit. Never use tauri-action / action-gh-release with a body on a published release.
To rebuild one platform for an existing tag, dispatch that workflow from main (so the upload-only YAML is used) with the tag input. Do not gh run rerun a tag-push job whose workflow still rewrites the release body:
gh workflow run "Windows Release" --ref main -f tag=vX.Y.Z -f signing_policy=release-signing -f publish=true
Details: docs/app-updates.md.
PR Expectations
Every PR should include:
- A clear statement of the user-facing problem solved.
- A summary of changed files and new abstractions.
- Tests added or updated.
- Manual smoke steps when UI or platform behavior is affected.
- Known limitations and explicit follow-up tasks.
For the research-workbench roadmap, use this ordering:
- ExecutionContext v0: context registry, SSH/WSL modeling, probe result model, no real long-running jobs yet.
- Run Manager v1: persisted run/job records, status lifecycle, local/shell/SSH-direct mockable runner, harvest model.
- Workspace Manifest v1: typed project layout, save/register APIs for scripts/data/results/literature/figures.
- Research Graph v0: link questions, decisions, data assets, runs, artifacts, and papers.
- UI integration: contexts panel, runs timeline, artifact/data/literature side panels.
