Flow-Like is a visual flow/automation platform with a Rust backend (Tauri desktop + multi-deployment API) and a Next.js/React frontend. It lets users build node-based flow programs, execute them locally or in the cloud, and extend them via WASM nodes.
packages/core — Core Rust runtime (flow execution engine)
packages/catalog/ — Built-in nodes grouped by domain (std, data, web, llm, …)
packages/api — Shared API types and middleware
packages/types — Shared Rust types (flow-like-types)
packages/executor — Execution engine
packages/compiler — Flow compiler
packages/wasm — WASM sandbox runtime
apps/desktop/ — Tauri + Next.js desktop app
apps/backend/ — Multi-target backends (local, AWS, Kubernetes, Docker)
libs/ — Additional libraries
templates/ — WASM node templates (Rust, Python, TS, Go, …)
# Fast incremental check for a single package (prefer this over full build)
cargo check -p <package-name>
# Catalog nodes require the execute feature for heavy-dep nodes
cargo check -p flow-like-catalog-data --features execute
# Full workspace check
cargo check
# Run tests
cargo test -p <package-name># Lint / format
bunx biome check .
bunx biome format --write .
# Desktop dev
cd apps/desktop && bun run dev # Next.js only
cd apps/desktop && bun run dev:all # Tauri + Next.js
# Type-check
cd apps/desktop && bunx tsc --noEmitmise run dev:desktop # Auto-detects platformgit diffis fine. NEVER run git stash, reset, or any other destructive/state-mutating git command without explicit user confirmation. The user is actively working in the same repo.
- Edit files directly using file tools — don't generate scripts to perform edits.
- No diff-mode snippets — always return complete drop-in replacements.
- No self-explanatory comments. Keep comments minimal and precise.
- DRY: extract reusable functions/components; avoid large logic blocks.
- Prefer parallel subagent work for multi-step tasks; track progress in
todo/*.md.
- After editing, run
cargo check -p <package>(not a full build) to verify. - After finishing a task, run a final
cargo checkto catch any cross-package issues. - No unnecessary comments. Rust code should be self-documenting.
Nodes with heavy deps (ML libs, PDF parsers, HTTP clients, etc.) must gate execution behind --features execute:
# Cargo.toml
[features]
execute = ["dep:heavy-crate"]
[dependencies]
heavy-crate = { workspace = true, optional = true }#[cfg(feature = "execute")]
async fn run(&self, context: &mut ExecutionContext) -> flow_like_types::Result<()> { … }
#[cfg(not(feature = "execute"))]
async fn run(&self, _context: &mut ExecutionContext) -> flow_like_types::Result<()> {
Err(flow_like_types::anyhow!("This node requires the 'execute' feature"))
}get_node() and on_update() are never gated — they provide metadata.
- Pure: no side effects, deterministic → no execution pins.
- Impure: side effects or non-deterministic → requires execution pins (
in/out).
- Deactivate outgoing execution pins first (stops graph on failure).
- Execute logic.
- Activate outgoing execution pins and write pin values.
Input and output pins that carry the same value must have different name values:
// WRONG — names collide in context.get/set_pin_by_name()
node.add_input_pin("log", "Log", …);
node.add_output_pin("log", "Log", …);
// CORRECT
node.add_input_pin("input_log", "Log", …);
node.add_output_pin("output_log", "Log", …);- Set default values on pins where sensible.
- Use
Optionsfor enum dropdowns; set JSON Schema for struct pins. - Add
NodePermissiondeclarations for WASM nodes (native catalog nodes are trusted by default). - Use
NodeImagefor images,FlowPathfor files. - Add
Success/Errorpins only at true system boundaries (external APIs, DBs). For most nodes, justreturn Err(…). - Add node/pin descriptions and quality scores (
privacy,security,performance,governance,reliability,cost— 0–10). - When updating a node's pins, bump the node version.
- Multiple pins with the same name within one direction let the user add more pins of that type.
NetworkHttp, NetworkWebsocket, NetworkTcp, NetworkUdp, NetworkDns, StorageRead, StorageWrite, Variables, Cache, Streaming, Models, A2ui, OAuth, Functions
- Always verify user access to resources with
ensure_permission!(user, &app_id, &state, RolePermissions::<Permission>)and enforce in SQL queries. Check comparable endpoints for the pattern. - Annotate every endpoint with
utoipafor OpenAPI docs and SDK generation. Include a short user-facing description. - Optimize queries: use caching, avoid N+1 calls, think about high-frequency endpoints.
- TypeScript everywhere; functional components with hooks only.
useMemo/useCallbackfor perf; properuseEffectdependency arrays.- UI: shadcn components (already installed — import, don't recreate). Tailwind CSS for styling. Lucide icons.
- Avoid hardcoded color tokens; use design system tokens.
- Prefer
const/readonly; use?.and??. - Split large components into focused subcomponents (can colocate in the same file).
After every file edit, run Codacy CLI analysis on the modified file:
- Tool:
codacy_cli_analyzewithrootPath= workspace path,file= edited file path. - Fix any reported issues before moving on.
After any package manager operation (npm/bun/pnpm install, adding deps):
- Run
codacy_cli_analyzewithtool: "trivy"to check for vulnerabilities. - Resolve security issues before continuing.
Codacy identifiers: provider: gh, organization: Rheosoph, repository: flow-like.
PRs target dev. Run these locally before pushing — they match the CI pipeline:
# Clippy (same strict flags as CI)
cargo clippy -- -D clippy::correctness -D clippy::suspicious
# Format check
cargo fmt --check
# Security audit
cargo audit
# Tests (some require API keys via env vars)
cargo test -p <package-name>
# Frontend
cd apps/desktop && bunx biome check . && bunx tsc --noEmitUse conventional commit prefixes: feat:, fix:, refactor:, chore:, docs:, test:.
Keep the subject under 72 characters. The release changelog groups by these labels.
- Read before writing: always read existing code/patterns before modifying. Check neighboring files for conventions.
- Incremental verification: run
cargo check -p <pkg>after each file edit, not just at the end. Catch errors early. - Match existing patterns: when adding a new node, endpoint, or component, find the closest existing example and follow its structure.
- No speculative abstractions: solve the problem at hand. Don't add config, feature flags, or extension points for hypothetical future needs.
- Error messages matter: include enough context in error strings to diagnose without a debugger. Name the operation that failed and the value that was unexpected.
- Test at boundaries: validate external input (user input, API responses, file contents). Trust internal code paths and framework guarantees.