Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
d0eed96
Gate the child's store write in the cancel-wait test
vinniefalco Sep 20, 2026
ca820f9
Move workspace and launch filesystem work off the executor
vinniefalco Sep 20, 2026
0120b33
Type the emitter's debug and trust flags as enums
vinniefalco Sep 20, 2026
734be56
Strip causes from error Display; render chains at exits
vinniefalco Sep 20, 2026
4bbab21
Mark public error and wire types non-exhaustive
vinniefalco Sep 20, 2026
d09be7c
Attach discarded error causes to error variants
vinniefalco Sep 20, 2026
128ff3a
Retire mod.rs files in favor of named module files
vinniefalco Sep 20, 2026
af40fd7
Tighten lint attributes, doctests, and test re-exports
vinniefalco Sep 20, 2026
1e11096
Split parser and loopback roots; name vfs and wire modules
vinniefalco Sep 20, 2026
84a234a
Inject workspace clock and drop sentinel test sleeps
vinniefalco Sep 20, 2026
854e44b
Reword gateway doc summaries and add module docs
vinniefalco Sep 20, 2026
bc212bb
Reword doc summaries and add module headers, two families
vinniefalco Sep 20, 2026
e0c3434
Reword doc summaries and add //! lines in build and workshop
vinniefalco Sep 20, 2026
7d9fb91
Close plan: rust rulebook sweep
vinniefalco Sep 20, 2026
db0f375
Rename gateway-api to gateway-api-types and add Progress
vinniefalco Sep 20, 2026
c232046
Replace the status bar progress element with a barberpole
vinniefalco Sep 20, 2026
b67f172
Move the Workshop status bar to the Progress wire type
vinniefalco Sep 20, 2026
2a55700
Collapse progress to a busy flag and producer-owned text
vinniefalco Sep 20, 2026
b4029a9
Move progress into the gateway family as gateway-progress
vinniefalco Sep 20, 2026
5c8d7a8
Mark harness web crates and split files under 500 lines
vinniefalco Sep 20, 2026
c611e84
Make the Invariants marker mandatory by crate family
vinniefalco Sep 20, 2026
49d645e
Close plan: gateway-api-types progress
vinniefalco Sep 20, 2026
4e59eae
Centralize blocking-task and extractor-rejection mapping
vinniefalco Sep 20, 2026
5d899e8
Install routes per area behind tier-named constructors
vinniefalco Sep 20, 2026
bc7d654
Declare routes as typed registry entries with a tier kind
vinniefalco Sep 20, 2026
fd9e860
Type the admin reply shapes
vinniefalco Sep 20, 2026
ed471fe
Move the apply command body beside the other commands
vinniefalco Sep 20, 2026
3f11e6f
Close plan: gateway route decentralization
vinniefalco Sep 20, 2026
05a78e9
Move error_chain beside the error type it renders
vinniefalco Sep 20, 2026
0997cd7
Move route module tests to kebab siblings
vinniefalco Sep 20, 2026
39c7dbf
Share one crate walk across the architecture checks
vinniefalco Sep 20, 2026
eb1cb2e
Skip repeated and empty causes when rendering error chains
vinniefalco Sep 20, 2026
4e7ff25
Pin every event variant and task origin with tests
vinniefalco Sep 20, 2026
7fbaf01
Correct the walled-tier allowlist before it is built
vinniefalco Sep 20, 2026
3e5ac8b
Move build-independent code out of the walled tier
vinniefalco Sep 20, 2026
c4ebb81
Check that only the walled tier names its own modules
vinniefalco Sep 20, 2026
387c1ea
Unify the gateway error-source newtypes in one crate
vinniefalco Sep 20, 2026
15f0da5
Replace per-crate error wrappers with the shared ones
vinniefalco Sep 20, 2026
e337a76
Close plan: debt removal
vinniefalco Sep 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 0 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,6 @@ jobs:
RUSTFLAGS: -D warnings
run: cargo check --locked -p gateway-whisper-ffi --lib

- name: Check product dependency boundaries
run: cargo test -p gateway-stt --test it architecture

- name: Clippy
run: cargo clippy --workspace --exclude workshop --exclude workshop-server --exclude workshop-server-api --all-targets --all-features -- -D warnings

Expand Down
14 changes: 7 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ Multi-crate Rust workspace for the PromptForge pipeline engine, the harness that

- The four main products are PromptForge, Gateway, Workshop, and Harness
- Workshop crates are named workshop-* and must not depend on gateway crates; workshop crates may name the gateway public pair, the promptforge door, and `harness-api`
- Gateway's public surface is two root crates, `gateway-api` and `gateway-api-discovery`; everything else lives under crates/gateway/, a manifestless container private to the family - no outside crate may depend into it, and workshop crates may name only the public pair. Gateway crates must not depend on promptforge or workshop crates
- Gateway's public surface is two root crates, `gateway-api-types` and `gateway-api-discovery`; everything else lives under crates/gateway/, a manifestless container private to the family - no outside crate may depend into it, and workshop crates may name only the public pair. Gateway crates must not depend on promptforge or workshop crates
- Workshop crates live under crates/workshop/, a manifestless container private to the family - no outside crate may depend into it; the shell is crates/workshop/shell (package `workshop`), and the server and its subsystems sit beside it with short directory names
- Harness crates are named harness-*. Their public surface is one root crate, `harness-api`; everything else lives under crates/harness/, a fourth manifestless container private to the family, and `harness-api` is its one door - the only outside crate permitted to depend into it. harness-* crates may depend on `promptforge-api-runtime`, `promptforge-api-types`, `gateway-api`, `gateway-api-discovery`, and shared-* crates, never on workshop crates or on a private gateway crate; workshop crates may depend on harness-* only through `harness-api`; promptforge-* and gateway-* crates must not depend on harness crates
- Harness crates are named harness-*. Their public surface is one root crate, `harness-api`; everything else lives under crates/harness/, a fourth manifestless container private to the family, and `harness-api` is its one door - the only outside crate permitted to depend into it. harness-* crates may depend on `promptforge-api-runtime`, `promptforge-api-types`, `gateway-api-types`, `gateway-api-discovery`, and shared-* crates, never on workshop crates or on a private gateway crate; workshop crates may depend on harness-* only through `harness-api`; promptforge-* and gateway-* crates must not depend on harness crates
- The composed topology rule: a crate in a family container (crates/promptforge/, crates/gateway/, crates/workshop/, crates/harness/) may depend only on crates at the crates/ root and its own siblings; the root is the public layer. Crates named build-* are meta tooling, exempt from container privacy
- PromptForge crates are named promptforge-* and must not depend on gateway, workshop, or harness crates
- PromptForge is one door: crates outside the promptforge-* family may depend only on promptforge-api-runtime and promptforge-api-types, never on the internal promptforge-* substrate crates; the crates under crates/promptforge/ are private to the family, and promptforge-api-runtime is the only outside crate permitted to depend into them
- The Workshop shell (the `workshop` crate) depends on `workshop-server-api` and never on `workshop-server`; the facade is the shell's entire view of the server
- Shared crates are named shared-*, contain the public API surface across products and downstream crates, and must not depend on any product crates. PromptForge's own public surface is promptforge-api-runtime and promptforge-api-types, named promptforge-* now that the types crate has left shared-*; Gateway's is gateway-api and gateway-api-discovery, named gateway-* now that both have left shared-*
- Shared crates are named shared-*, contain the public API surface across products and downstream crates, and must not depend on any product crates. PromptForge's own public surface is promptforge-api-runtime and promptforge-api-types, named promptforge-* now that the types crate has left shared-*; Gateway's is gateway-api-types and gateway-api-discovery, named gateway-* now that both have left shared-*; the types crate carries the wire vocabulary only, never code
- Crates named build-* are for building specific outputs
- Dependency rules bind all kinds: normal, dev, build, and target-specific dependencies

Expand All @@ -41,7 +41,7 @@ Multi-crate Rust workspace for the PromptForge pipeline engine, the harness that
- Behavior changes ship with tests in the same change. Preserve product and behavior tests during refactors. Structural tests that an approved plan identifies as unsupported may be removed without replacement by another structural proxy.
- A Cargo feature gates a real constraint such as a toolchain requirement or heavy native build. It does not describe product shape. Feature-disabled builds must not leak optional types into core paths.
- Runtime and serve paths never compile native dependencies or invoke build tools. Library and serve paths return failures instead of exiting the process or installing process-global state.
- Long-running work reports through `shared-progress`. Producers report operation state, hosts forward it, and renderers format it.
- Long-running gateway work reports through `gateway-progress`, a private gateway family crate: a producer begins an activity with a text, replaces the text as work moves, and drops the guard when done. Consumers outside the family read only the `Progress` wire type from `gateway-api-types`.
- Unsafe code stays in its explicitly owned boundary. Every unsafe block documents its safety invariants immediately before the block.
- Comments explain a non-obvious constraint, ordering requirement, or workaround. Every platform or external-bug workaround cites its upstream issue URL in the explanatory comment.

Expand All @@ -56,12 +56,12 @@ Multi-crate Rust workspace for the PromptForge pipeline engine, the harness that
## Structural Rules

- Dependencies flow one way: shell -> features -> services -> vocabulary. Never add a dependency from a lower tier to a higher one. If Cargo rejects a cycle, the design is wrong, not the graph. On the SPA side, lazy-loaded panels never import the boot shell; shared code lives in services/ or base/.
- Every workshop-* and harness-* crate's lib.rs opens with a //! doc carrying a `## Invariants` marker that lists what the crate may depend on and what it may not. Read it before adding an import. Every SPA concern directory (ui/editor/, ui/agent/, etc.) has the same in its index.ts.
- No file exceeds 500 lines. If an edit would push a file past 500, split first, then edit. `cargo test -p build-xtask` enforces the tier graph, the lint inheritance, the ceiling over the Rust files in the workshop-* and harness-* crates carrying the marker, and the product-boundary matrix above (including the one-door rules for promptforge and harness and the container privacy rules for crates/promptforge/, crates/gateway/, crates/workshop/, crates/harness/, and the nested crates/gateway/stt/ subsystem, whose only family-visible crate is gateway-stt) across every workspace manifest; `cargo test -p gateway-stt --test it architecture` checks the same product matrix from cargo metadata; the Tauri shell (the `workshop` crate) is exempt until the headless agent mode plan.
- Every workshop-* and harness-* crate's lib.rs (including harness-api) opens with a //! doc carrying a `## Invariants` marker that lists what the crate may depend on and what it may not. The marker is mandatory for those families by package name; a family crate without it fails `cargo test -p build-xtask`. The Tauri shell (the `workshop` crate) is exempt. Read the marker before adding an import.
- No file in a crate carrying the marker exceeds 500 lines. If an edit would push a file past 500, split first, then edit. `cargo test -p build-xtask` enforces the tier graph, the mandatory marker, the lint inheritance, the ceiling over the Rust files in every workshop-* and harness-* crate plus any other crate carrying the marker, and the product-boundary matrix above (including the one-door rules for promptforge and harness and the container privacy rules for crates/promptforge/, crates/gateway/, crates/workshop/, crates/harness/, and the nested crates/gateway/stt/ subsystem, whose only family-visible crate is gateway-stt) across every workspace manifest; the Tauri shell (the `workshop` crate) is exempt from the marker and the ceiling until the headless agent mode plan.
- Source directories are flat by default. A subdirectory of source files must contain at least three files; one or two files belong beside the parent module as `foo-bar.rs` (parent stem, dash, kebab label), wired with an explicit path attribute so the module name stays clean: `#[path = "foo-bar.rs"] mod bar;`. The two forms are convertible in both directions: when a `foo-*.rs` sibling group grows to three files, rehydrate it into a `foo/` subdirectory in standard module layout (`foo/bar.rs` beside `foo.rs`) and drop the path attributes; when a subdirectory shrinks below three files, flatten it back to kebab siblings. Apply whichever conversion applies when you touch files in a group on the wrong side of the line. Top-level `tests/` and `benches/` trees are exempt; they follow Cargo target conventions.

## SPA and CSS Rules

- CSS lives beside its TypeScript, never in a separate styles/ tree. A designer finds the styles for the agent chat at ui/agent/agent-session.css, not by grepping a flat directory. Every feature directory is self-contained: .ts, .css, and index.ts together.
- CSS lives beside its TypeScript, never in a separate styles/ tree. A designer finds the styles for the agent chat at parts/agent/agent-session.css, not by grepping a flat directory. Every feature directory is self-contained: .ts, .css, and index.ts together.
- No raw color, size, or spacing values in component CSS. Use --ws-* tokens from tokens/. Primitives go in tokens/base.css, intent aliases in tokens/semantic.css, per-component overrides in tokens/component.css. A designer themes the app by editing semantic.css.
- No `localStorage`. The SPA never reads or writes browser storage; every persisted value goes through the `ui-storage` adapter to the server. UI state has two homes by scope: account state (preferences and ephemera alike, such as editor toggles, zoom, recent files, and command history) goes to `ui-state.json` in the state directory (the `workshop-user-state` crate, `/user/state`), and workspace-scoped state (anything that should travel with the `.pfwork` document) goes to the workspace file through the server (`/workspace/file/state`). A new persisted value is a new allow-listed key in one of those two buckets, added on the server first.
65 changes: 39 additions & 26 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[workspace]
resolver = "3"
members = ["crates/*", "crates/promptforge/lua", "crates/promptforge/parser", "crates/promptforge/store", "crates/promptforge/vfs", "crates/promptforge/model-client", "crates/gateway/app", "crates/gateway/cloud-providers", "crates/gateway/config", "crates/gateway/config-ui", "crates/gateway/local", "crates/gateway/logging", "crates/gateway/protocol", "crates/gateway/routing", "crates/gateway/web-search", "crates/gateway/stt/api", "crates/gateway/stt/engine", "crates/gateway/stt/backend-whisper", "crates/gateway/stt/whisper-ffi", "crates/workshop/shell", "crates/workshop/server", "crates/workshop/server-api", "crates/workshop/gateway", "crates/workshop/menu", "crates/workshop/protocol", "crates/workshop/registry", "crates/workshop/status", "crates/workshop/support", "crates/workshop/user-state", "crates/workshop/workspace", "crates/harness/runner", "crates/harness/models", "crates/harness/capabilities", "crates/harness/log", "crates/harness/sessions", "crates/harness/web", "crates/harness/webfetch", "crates/harness/web-search"]
members = ["crates/*", "crates/promptforge/lua", "crates/promptforge/parser", "crates/promptforge/store", "crates/promptforge/vfs", "crates/promptforge/model-client", "crates/gateway/app", "crates/gateway/cloud-providers", "crates/gateway/config", "crates/gateway/config-ui", "crates/gateway/local", "crates/gateway/logging", "crates/gateway/progress", "crates/gateway/protocol", "crates/gateway/routing", "crates/gateway/web-search", "crates/gateway/stt/api", "crates/gateway/stt/engine", "crates/gateway/stt/backend-whisper", "crates/gateway/stt/whisper-ffi", "crates/workshop/shell", "crates/workshop/server", "crates/workshop/server-api", "crates/workshop/gateway", "crates/workshop/menu", "crates/workshop/protocol", "crates/workshop/registry", "crates/workshop/status", "crates/workshop/support", "crates/workshop/user-state", "crates/workshop/workspace", "crates/harness/runner", "crates/harness/models", "crates/harness/capabilities", "crates/harness/log", "crates/harness/sessions", "crates/harness/web", "crates/harness/webfetch", "crates/harness/web-search"]
# crates/shared-ui is not a Rust crate: it is the shared TypeScript+CSS
# package both esbuild-built UIs consume, so the crates/* glob skips it.
# crates/promptforge, crates/gateway, crates/workshop, and crates/harness
Expand All @@ -27,13 +27,14 @@ base64 = "0.22"
bytes = "1"
promptforge-api-runtime = { path = "crates/promptforge-api-runtime", version = "0.3.0" }
promptforge-api-types = { path = "crates/promptforge-api-types", version = "0.3.0" }
gateway-api = { path = "crates/gateway-api", version = "0.3.0" }
gateway-api-types = { path = "crates/gateway-api-types", version = "0.3.0" }
gateway-cloud-providers = { path = "crates/gateway/cloud-providers", version = "0.3.0" }
gateway = { path = "crates/gateway/app", version = "0.3.0" }
gateway-config = { path = "crates/gateway/config", version = "0.3.0" }
gateway-config-ui = { path = "crates/gateway/config-ui", version = "0.3.0" }
gateway-local = { path = "crates/gateway/local", version = "0.3.0" }
gateway-logging = { path = "crates/gateway/logging", version = "0.3.0" }
shared-error-source = { path = "crates/shared-error-source", version = "0.3.0" }
shared-loopback = { path = "crates/shared-loopback", version = "0.3.0" }
gateway-protocol = { path = "crates/gateway/protocol", version = "0.3.0" }
gateway-api-discovery = { path = "crates/gateway-api-discovery", version = "0.3.0" }
Expand All @@ -51,7 +52,7 @@ gateway-routing = { path = "crates/gateway/routing", version = "0.3.0" }
promptforge-lua = { path = "crates/promptforge/lua", version = "0.3.0" }
promptforge-model-client = { path = "crates/promptforge/model-client", version = "0.3.0" }
promptforge-parser = { path = "crates/promptforge/parser", version = "0.3.0" }
shared-progress = { path = "crates/shared-progress", version = "0.3.0" }
gateway-progress = { path = "crates/gateway/progress", version = "0.3.0" }
gateway-stt = { path = "crates/gateway/stt/api", version = "0.3.0" }
promptforge-store = { path = "crates/promptforge/store", version = "0.3.0" }
promptforge-vfs = { path = "crates/promptforge/vfs", version = "0.3.0" }
Expand Down
Loading
Loading