Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
3a9a8e3
Add shared-vfs skeleton with canonical interned paths
vinniefalco Sep 12, 2026
3ce38ff
Define Vfs and VfsAccess traits and policy types
vinniefalco Sep 12, 2026
e32e031
Add VfsRef handle and Access capability with claims
vinniefalco Sep 12, 2026
23aaa83
Add mount router, builder, and handle overlays
vinniefalco Sep 12, 2026
69faa2f
Add in-memory VFS backend with bounded glob matching
vinniefalco Sep 12, 2026
f41d586
Add thin host filesystem backend to shared-vfs
vinniefalco Sep 12, 2026
0df2a7e
Add promptforge-vfs policy crate with mode gate
vinniefalco Sep 12, 2026
c452721
Replace the store trait and backends with a VFS facade
vinniefalco Sep 12, 2026
9df19b1
Pivot the executor API from StoreRef to VfsRef
vinniefalco Sep 12, 2026
6d2e089
Make store ops leaf yields with fatal determinism conflicts
vinniefalco Sep 12, 2026
656b536
Add Bashkit FsBackend adapter over the VFS handle
vinniefalco Sep 12, 2026
1680352
Close plan: vfs foundation
vinniefalco Sep 12, 2026
27354d9
Add the test-namespace and VFS debt removal plan
vinniefalco Sep 12, 2026
4fc4825
Remove test-only re-exports and relocate test imports
vinniefalco Sep 12, 2026
a4c7876
Remove the two tracked vibe ledger files
vinniefalco Sep 12, 2026
1c550ee
Remove the promptforge-bashkit spike crate
vinniefalco Sep 12, 2026
fca9d4e
De-intern VfsPath and close the manifest test bypass
vinniefalco Sep 12, 2026
432f268
Make handle acquisition fallible instead of panicking
vinniefalco Sep 12, 2026
ec14591
Close plan: test-namespace vfs-debt
vinniefalco Sep 12, 2026
a749458
[WIP] Plan: Dependency rules, PR 35 code fixes, and the VFS observati…
vinniefalco Sep 12, 2026
c8947b9
Land dependency-rule revisions and the design move
vinniefalco Sep 12, 2026
919f85e
Rename shared-protocol to gateway-protocol, add Shared rule
vinniefalco Sep 12, 2026
a90bed3
Fix claims-release ordering and unix mode lint
vinniefalco Sep 12, 2026
51755f0
Add the VFS operation-observation hook
vinniefalco Sep 12, 2026
e75a5f1
Close plan: dependency-rules-vfs-hook
vinniefalco Sep 12, 2026
5b79db3
Drain in-flight I/O tasks before delivering the run result
vinniefalco Sep 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,36 @@

Multi-crate Rust workspace for the PromptForge pipeline runtime, inference gateway, and Workshop desktop product.

## Principles

- Do more with less. Prefer simple, foundational primitives over specific solutions: a primitive that naturally enables today's functionality and also generalizes beats a custom mechanism specified as a laundry list of requirements. Generality is the payoff, not a goal.
- When evaluating how to implement a capability, check whether the existing facilities subsume the work before building new machinery. Prioritize in this order:
1. Reuse an existing facility
2. Make the smallest improvement to an existing facility which enables the capability.
3. Add a new facility. New machinery must have a material benefit beyond tidiness.
- When improving an existing facility, prefer an improvement that serves a problem class beyond the current case over one that solves only the case at hand, when the general shape costs no more.

## Roles

- Workshop is a user-facing agentic development environment: a Tauri desktop application with an HTML/CSS/TypeScript UI
- PromptForge is the runtime execution engine for the PromptForge Prompting Language: structured Markdown files with live Lua code fences
- Gateway is an independent service that proxies local and remote inference through one OpenAI-compatible HTTP and WebSocket endpoint

## Structure

- The three main products are PromptForge, Gateway, and Workshop
- Workshop crates are named workshop-* and must not depend on gateway crates
- Gateway crates are named gateway-* and must not depend on promptforge or workshop crates
- PromptForge crates are named promptforge-* and must not depend on gateway or workshop crates
- Shared crates are named shared-*, contain the public API surface across products and downstream crates, and must not depend on any product crates
- Crates named build-* are for building specific outputs
- Dependency rules bind all kinds: normal, dev, build, and target-specific dependencies

## Engineering

- Prefer types and compiler checks, then behavior tests and deterministic fault injection. Add a structural check only with explicit user approval for a stable product or security boundary that has no ordinary equivalent.
- Repository policy binds plans. A plan cannot introduce a source parser, snapshot, allowlist, count, ceiling, topology check, import walker, or other structural enforcement unless the user explicitly approves that exception.
- 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.
- Keep four cross-product dependency rules: Gateway product crates cannot depend on Workshop product crates; PromptForge product crates cannot depend on Gateway or Workshop product crates; Gateway product crates cannot depend on PromptForge product crates; Workshop product crates cannot depend on Gateway product crates.
- Do more with less. Before adding a frontmatter field, configuration key, public type, or resolution path, determine whether sandboxed Lua, the run-scoped store, or the catalog already carries the work. New machinery must have a material benefit beyond tidiness.
- 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.
Expand Down
65 changes: 42 additions & 23 deletions Cargo.lock

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

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,17 @@ 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-loopback = { path = "crates/shared-loopback", version = "0.3.0" }
shared-protocol = { path = "crates/shared-protocol", version = "0.3.0" }
gateway-protocol = { path = "crates/gateway-protocol", version = "0.3.0" }
shared-sidecar = { path = "crates/shared-sidecar", version = "0.3.0" }
shared-vfs = { path = "crates/shared-vfs", version = "0.3.0" }
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-stt = { path = "crates/gateway-stt", version = "0.3.0" }
promptforge-store = { path = "crates/promptforge-store", version = "0.3.0" }
promptforge-vfs = { path = "crates/promptforge-vfs", version = "0.3.0" }
promptforge-webfetch = { path = "crates/promptforge-webfetch", version = "0.3.0" }
promptforge-tool-picker = { path = "crates/promptforge-tool-picker", version = "0.3.0" }
promptforge-tools = { path = "crates/promptforge-tools", version = "0.3.0" }
Expand Down
2 changes: 0 additions & 2 deletions crates/gateway-config/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ pub use companion::{
SpeculativeConfig,
};
pub(crate) use imp::reject_profiles_directory;
#[cfg(test)]
pub(crate) use interpolate::interpolate;
pub(crate) use interpolate::interpolate_value;
use stt::RawSttPipelineConfig;
pub use stt::{
Expand Down
1 change: 1 addition & 0 deletions crates/gateway-config/src/config/tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::interpolate::interpolate;
use super::*;

const SAMPLE: &str = r#"
Expand Down
2 changes: 1 addition & 1 deletion crates/gateway-local/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ documentation = "https://cppalliance.github.io/promptforge/"
async-trait.workspace = true
flate2.workspace = true
gateway-config.workspace = true
shared-protocol.workspace = true
gateway-protocol.workspace = true
gateway-routing.workspace = true
shared-progress.workspace = true
rand.workspace = true
Expand Down
8 changes: 1 addition & 7 deletions crates/gateway-local/src/artifacts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

mod archive;
mod assets;
mod confine;
pub(crate) mod confine;
mod digest;
mod download;
mod progress;
Expand All @@ -33,8 +33,6 @@ use tokio_util::sync::CancellationToken;

use crate::error::LocalError;

#[cfg(test)]
use archive::extract_archive;
use archive::extract_archive_with_progress;
use archive::find_executable;
use archive::require_executable;
Expand All @@ -56,10 +54,6 @@ pub(crate) use confine::{
enforce_private_cache_root, ensure_cache_directory, part_path, remove_cache_entry,
rename_confined, safe_relative_path, validate_cache_path, write_synced,
};
// Test builds only: the resume tests in this module and cache.rs build the
// marker path; the download path itself imports it from confine directly.
#[cfg(test)]
pub(crate) use confine::source_marker_path;
pub(crate) use digest::hex_digest;
pub use digest::parse_expected_digest;
pub(crate) use download::{download_with_progress, hub_bearer_token_from_env};
Expand Down
3 changes: 2 additions & 1 deletion crates/gateway-local/src/artifacts/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ use tempfile::TempDir;
use shared_progress::{EventState, ProgressHub};
use tokio_util::sync::CancellationToken;

use super::archive::{extract_archive_with_progress, safe_archive_path};
use super::archive::{extract_archive, extract_archive_with_progress, safe_archive_path};
use super::assets::ArchiveRef;
use super::confine::source_marker_path;
use super::digest::file_digest;
use super::download::{hub_bearer_token, is_huggingface_https};
use super::progress::{DownloadProgress, TreeProgress};
Expand Down
2 changes: 1 addition & 1 deletion crates/gateway-local/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ mod tests {
use tempfile::TempDir;

use super::*;
use crate::artifacts::source_marker_path;
use crate::artifacts::confine::source_marker_path;
use crate::testsupport::{FakeServer, hex_sha256};

/// Test double recording the progress callbacks a download drives.
Expand Down
2 changes: 1 addition & 1 deletion crates/gateway-local/src/dialect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::error::LocalError;
const PROPS_TIMEOUT: Duration = Duration::from_secs(5);

/// Byte ceiling for a dialect-probe JSON body (HYGIENE-BOUNDS-001).
const MAX_PROBE_BODY: u64 = shared_protocol::http_util::MAX_JSON_BODY as u64;
const MAX_PROBE_BODY: u64 = gateway_protocol::http_util::MAX_JSON_BODY as u64;

/// Evidence from a local child's `/props`, `/v1/models`, and sidecar metadata
/// used to select a tool-calling dialect.
Expand Down
2 changes: 1 addition & 1 deletion crates/gateway-local/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
//! header inspection in [`gguf`].
//!
//! Failures are reported as [`LocalError`]; an explicit teardown failure is
//! reported as [`ShutdownError`](shared_protocol::ShutdownError).
//! reported as [`ShutdownError`](gateway_protocol::ShutdownError).
//! The crate contains no HTTP routing and no error envelopes; those live in
//! the gateway crate.

Expand Down
6 changes: 3 additions & 3 deletions crates/gateway-local/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ use std::thread;
use std::time::Duration;

use gateway_config::{Config, LocalModelConfig, ModelKind, QueuePolicy, ThinkingMode};
use gateway_protocol::ShutdownError;
use gateway_routing::queue::DominionQueue;
use gateway_routing::{Endpoint, Model, dominion_queues};
use shared_progress::ProgressHandle;
use shared_protocol::ShutdownError;
use tokio_util::sync::CancellationToken;

use crate::artifacts::{self, ArtifactStore, ProvisionedServer, ServerSelection};
Expand Down Expand Up @@ -658,7 +658,7 @@ impl LocalRuntime {

/// Removes one started model and its upstream from the runtime, returning
/// the model so the caller can tear the child down through the
/// [`Upstream`](shared_protocol::upstream::Upstream) seam (which disables
/// [`Upstream`](gateway_protocol::upstream::Upstream) seam (which disables
/// respawn before killing the process). Returns `None` when no started
/// model carries `name`.
///
Expand All @@ -682,7 +682,7 @@ impl LocalRuntime {
/// Dropping the runtime does not guarantee child termination, because the
/// routing table holds `Arc<dyn Upstream>` clones of these same models, so
/// the runtime is not the sole owner (PFGL-MOD-001). This drives an explicit
/// teardown through the [`Upstream`](shared_protocol::upstream::Upstream) seam so a
/// teardown through the [`Upstream`](gateway_protocol::upstream::Upstream) seam so a
/// profile switch frees the old children's VRAM deterministically before the
/// replacement profile's children start. Every child is torn down even if an
/// earlier one fails, so one stuck child never strands the rest.
Expand Down
2 changes: 1 addition & 1 deletion crates/gateway-local/src/server/support.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use super::{
SpawnRequest,
};
use crate::error::LocalError;
use shared_protocol::http_util::MAX_JSON_BODY;
use gateway_protocol::http_util::MAX_JSON_BODY;

/// A spawn callback: builds a child from a [`SpawnRequest`].
pub(super) type SpawnFn = Box<dyn FnMut(&SpawnRequest<'_>) -> Result<Child> + Send>;
Expand Down
Loading
Loading