Skip to content

Coding patterns ​

Architecture rules ​

  1. engine owns workflow model rules, execution semantics, templates, and ports.
  2. providers is an adapter crate that implements AiPort for BYOK providers.
  3. orchestration composes runtime, state, persistence, tools, projects, settings, and app services.
  4. desktop is only a transport adapter: Tauri commands and app bootstrap.
  5. ui owns rendering and interaction, via typed desktop invokes/events.
  6. engine must not depend on HTTP clients, filesystem/tool I/O, Tauri, providers, orchestration, desktop, or UI.
  7. orchestration calls engine APIs; it never duplicates workflow validity or execution rules.
  8. Add a port/trait only when a consumer is typed on it; otherwise call the concrete type.
  9. Existing boundaries: engine/src/ports/ (AiPort, ToolPort), providers/src/client.rs (AiClient), and ui/src/api.ts (typed Tauri invoke/event wrappers).

Ownership by concern ​

ConcernSource of truth
Workflow types, defaults, WorkflowSettingscrates/engine/src/graph/workflow.rs
Graph validity and execution layer ordercrates/engine/src/graph/validation.rs
Batch / headless run semanticscrates/orchestration/src/run/execution/headless.rs
Interactive pause/resume semanticscrates/engine/src/execution/interactive_engine/
Node invocation and prompt assemblycrates/engine/src/execution/node_invocation.rs
Node templates, defaults, and locked fieldscrates/engine/src/template/
LLM invocation contract (AiPort, AgentRequest)crates/engine/src/ports/outbound.rs
Tool execution contract (ToolPort)crates/engine/src/ports/outbound.rs, crates/orchestration/src/run/execution/tool_port.rs
Human input and tool approval resume behaviorcrates/engine/src/execution/interactive_engine/
LLM transport mapping and tool-arg repaircrates/providers/src/mapping/, rig_adapter/
Provider client (AiClient, create_provider)crates/providers/src/client.rs, lib.rs
UI desktop seamcrates/ui/src/api.ts
App backend composition and IPC surfacecrates/orchestration/src/backend/mod.rs
Run execution, shared context, callable agents, execution cwdcrates/orchestration/src/run/execution/
Mutable run/edit state transitionscrates/orchestration/src/run/state.rs
App workflow file storecrates/orchestration/src/adapters/storage/app_workflow_store.rs
Project metadata and workflow bindingscrates/orchestration/src/adapters/storage/project_store.rs
Project workflow files (.flow/workflows/)crates/orchestration/src/adapters/storage/project_workflow_store.rs
Saved agent definitionscrates/orchestration/src/adapters/storage/agent_store.rs
Skill discovery (read-only)crates/orchestration/src/adapters/storage/skill_store.rs
Provider readiness and API-key resolutioncrates/orchestration/src/settings/provider.rs
Settings persistencecrates/orchestration/src/adapters/storage/settings_store.rs
Tool registry and approvalcrates/orchestration/src/tool/
Tauri command/event surfacecrates/desktop/src/lib.rs
Frontend invoke wrappers and UI state wiringcrates/ui/src/api.ts, crates/ui/src/context/
Frontend DTO typescrates/ui/src/lib/types/index.ts
Editor layout and panelscrates/ui/src/screens/EditorScreen.tsx, crates/ui/src/panels/
Sidebar and navigationcrates/ui/src/components/sidebar/
Conversation and tool bubblescrates/ui/src/components/conversation/

Runtime semantics ​

These live in crates/orchestration/src/run/** and crates/engine/src/execution/**, never in UI or desktop.

  1. Shared context: WorkflowSettings.shared_context is trimmed and appended to every node's system prompt for the run, and to ad-hoc/saved subagent prompts.
  2. Execution cwd: the backend resolves it from the exact selected project's default_execution_cwd (else project root). App workflow/chat runs get an isolated app-managed folder under {data_local}/openflow/workspaces/. Filesystem tools run there.
  3. Callable agents: AgentNodeConfig.callable_agents (or allow_all_callable_agents) is snapshotted at run start by engine::resolve_callable_agent_snapshots into CallableAgent records, the same type persisted agents use (orchestration::AgentDefinition alias). Invoked via runtime builtins openflow_call_subagent and openflow_declare_subagents.
  4. Provider routing: AgentNodeConfig.provider_id beats WorkflowSettings.provider_id, which beats the active settings provider. The run-scoped router sends each AgentRequest to that provider; errors surface with no cross-provider failover.
  5. Model default: at run prep, an empty AgentNodeConfig.model inherits the effective ProviderProfile.default_model. An explicit node model always wins.
  6. Workflow storage split: app-local workflows live in workflows.json; project-linked workflows persist under {project}/.flow/workflows/. AppBackend merges both on load.
  7. Tool concurrency: shared tools may run in parallel within a batch; exclusive tools take a per-tool semaphore in ToolPortImpl.

Persistence conventions ​

  1. All app persistence files live under {data_local}/openflow/: agents.json, projects.json, workflows.json, settings.json, mcp-secrets.json.
  2. Project workflow files use the {workflowId}.workflow.json suffix under .flow/workflows/.
  3. Provider API keys persist in plaintext in settings.json, on each ProviderProfile.api_key. The UI loads settings redacted and fetches keys over dedicated IPC. Env vars (OPENAI_API_KEY, ANTHROPIC_API_KEY, provider-specific ones) stay fallbacks.
  4. MCP inputs and OAuth credentials persist in mcp-secrets.json (plaintext, mode 0600 on Unix). MCP config stores only opaque mcp-secret:v1:* refs.

Implementation conventions ​

  1. Constants go at the top of the file, named by intent (*_WIDTH, *_HEIGHT, *_GAP, *_PADDING).
  2. Helpers sit near their use, private unless reused.
  3. Tests go in #[cfg(test)] mod tests in the behavior's file.
  4. Typed thiserror errors with actionable messages.
  5. Where order affects behavior, sort IDs for determinism (as in validation.rs and runner.rs).
  6. Mutate state through dedicated WorkflowRunState / AppBackend methods, not direct map/vector edits across modules.
  7. UI sidebar lists use the shared primitives (SidebarNavButton, SidebarIconButton, SidebarList, SidebarListRow) for consistent hover/rename.
  8. With no node selected, hide the inspector. The right column shows WorkflowSettingsPanel or InspectorPanel by editor state.

Error handling rules ​

  1. Map external/system errors into local domain language at crate boundaries.
  2. Fallible operations return Result<_, _>. No panics outside tests.
  3. expect(...) only for invariants a validated flow guarantees.

Test strategy ​

  1. New behavior gets focused unit tests in the same module.
  2. Test visible behavior, not private implementation details.
  3. For workflow logic changes, cover:
    • validation outcomes
    • execution layer ordering
    • upstream input shape
    • shared context injection
    • callable agent snapshot resolution
    • execution cwd resolution
    • failure propagation

Testing workflows defines acceptance and live-AI checks. The architecture contract defines layer rules.

Dependency boundary ​

  1. Add workspace deps to the root Cargo.toml first, then to crate manifests.
  2. Keep crate dependencies minimal and role-specific:
    • engine: graph, execution, templates, conversations, tools, and ports only.
    • providers: HTTP + provider payload parsing/auth only.
    • orchestration: runtime/state/persistence/execution.
    • desktop: Tauri adapter only.
    • ui: frontend rendering and interaction only.

Local run commands ​

TaskCommand
Start the desktop app./scripts/start.sh
Start the frontend onlynpm --prefix crates/ui run dev
Typecheck the frontendnpm --prefix crates/ui run typecheck

Test file layout ​

PatternWhenExample
Sibling *_tests.rsLarge ported or multi-case suitesadapters/tool_impl/edit/patch_tests.rs declared in parent mod.rs
Inline #[cfg(test)] mod testsSmall unit tests colocated with one source fileadapters/tool_impl/edit/io.rs
Folder tests.rsIntegration tests for a module subtreerun/execution/tests.rs

Declare sibling test modules in the parent mod.rs:

rust
#[cfg(test)]
mod patch_tests;

One pattern per file: sibling file or inline block, never both.

Change checklist ​

  1. Edit the smallest owning module first.
  2. Add or update tests in the same PR.
  3. Run:
bash
cargo fmt --all --check
cargo clippy --workspace --all-targets
cargo clippy-max
cargo nextest run --workspace
  1. If behavior contracts changed, update this doc, AGENTS.md, and glossary.md as needed.

Released under the MIT License.