Why Unified Field
Why Unified Field
Two GitHub templates share the same accounts, UI shell, and Rust APIs. Embedded runs in one process; Remote fleet splits runtimes into services you can scale separately.Template to platform
Start with a GitHub template
Choose Embedded or Remote fleet. Both repositories wire in Unified Field products, and you decide what stays in your application.Embedded or Remote fleetUnified Field platformYour application
Accounts and a first-run path
Sign-in and account settings come from Lepton, the accounts product. The welcome page and route-aware spotlight tours give new users a way into the applications they can access.Lepton · /user/account-settings
Transparent data path
Valence keeps typed models and access policies together in code you can inspect. The schema records who may read or change each field and when, so applications can show what data they use and why.Valence · /valence/schema/counter/id/singleton
User context follows the work
Higgs builds user-scoped Valence in a server function. When that request schedules work or publishes an event, Boson, Chronon, and Photon rebuild the captured actor through the same factory instead of silently switching to System access.Higgs · src/server.rs
use boson_core::ExecutionContext;
use boson_macros::task;
use boson_valence_identity::valence_from_context;
use higgs::Higgs;
use leptos::prelude::*;
// `auth` rejects callers who aren't signed in.
#[higgs_macros::server(auth)]
pub async fn queue_profile_rebuild() -> Result<(), ServerFnError> {
let ctx = Higgs::from_request().await?;
let valence = ctx.valence().map_err(ServerFnError::new)?;
let user_id = valence
.actor()
.user_id()
.ok_or_else(|| ServerFnError::new("expected a signed-in user"))?
.to_string();
RebuildProfile::send_with(
serde_json::json!({ "User": { "user_id": user_id } }),
RebuildProfileParams {
user_id: user_id.clone(),
},
)
.await
.map_err(ServerFnError::new)?;
Ok(())
}
#[task(name = "rebuild_profile")]
async fn rebuild_profile(
ctx: Box<dyn ExecutionContext>,
user_id: String,
) -> boson_core::Result<()> {
// Same user as the server function. Chronon scripts and Photon
// subscribers rebuild context from the same ValenceFactory.
let valence = valence_from_context(ctx.as_ref())?;
tracing::info!(rebuilt_user = valence.actor().user_id(), %user_id);
Ok(())
}Search, notifications, and history
Workspace search and notifications are part of the signed-in shell. Record-history views can be added to your own applications, but that UI isn't mounted on this public site.Live UI and deployment
Photon keeps product views current. The Embedded template runs the platform in one process; Remote fleet separates services and runs Gluon and Nucleus for cloud placement and data-service control.Photon · /counter
Job definitions
Define Boson tasks and Chronon scripts with Rust macros. The same handler contracts run in-process or on remote workers, and both operator UIs are mounted on this site.Three samples here; the full set is on Resources.Valence schemaValence
Schema, generated model, and a read with a declared purpose
// build.rs
fn main() {
valence_codegen::build().expect("valence codegen failed");
}
// schemas/counter_valence_schema.rs
use valence::prelude::*;
valence_schema! {
Counter {
repository: "https://github.com/acme/counter",
table: "counter",
version: "0.1.0",
description: "Simple counter",
// No policies block: every actor except System is denied.
fields: [
id: { r#type: FieldType::String, primary_key: true, required: true },
value: { r#type: FieldType::Integer, required: true },
],
}
}
// src/lib.rs
use valence::{use_, Model};
valence::include_generated_models!();
let counter = Counter::get(
"home",
&valence,
use_!("Show the **counter value** on the home page."),
)
.await?;Boson taskBoson
Typed #[task] with retry settings, then enqueue
use std::sync::Arc;
use boson::{
configure, task, Boson, ExecutionContext, JsonExecutionContextFactory,
MemQueueBackend,
};
#[task(name = "process_order", max_attempts = 5, max_in_flight = 20)]
async fn process_order(
ctx: Box<dyn ExecutionContext>,
order_id: String,
amount_cents: u64,
) -> boson_core::Result<()> {
tracing::info!(actor = ctx.label(), %order_id, amount_cents);
Ok(())
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let boson = Boson::builder()
.queue_backend(Arc::new(MemQueueBackend::new()))
.execution_context_factory(JsonExecutionContextFactory)
.auto_registry()
.build()?;
configure(boson);
ProcessOrder::send_with(
serde_json::json!({"System": {"operation": "checkout"}}),
ProcessOrderParams {
order_id: "ord-42".into(),
amount_cents: 9900,
},
)
.await?;
Ok(())
}Chronon jobChronon
Typed #[chronon::script] scheduled with JobBuilder
use std::sync::Arc;
use chronon::prelude::*;
use chronon::InMemorySchedulerStore;
#[chronon::script(name = "nightly_cleanup")]
async fn nightly_cleanup(
ctx: Box<dyn ScriptContext>,
retention_days: u32,
) -> chronon::Result<()> {
println!("{}: retaining {retention_days} days", ctx.label());
Ok(())
}
#[tokio::main]
async fn main() -> chronon::Result<()> {
let chronon = Chronon::builder()
.scheduler_store(Arc::new(InMemorySchedulerStore::new()))
.context_factory(Arc::new(JsonScriptContextFactory))
.embedded()
.auto_registry()
.build()?;
let nightly = JobBuilder::new(&nightly_cleanup())
.name("nightly-schedule")
.cron("0 2 * * *")?
.timezone("UTC")
.params(NightlyCleanupParams { retention_days: 7 })
.build()?;
chronon.coordinator_service().upsert_job(nightly).await?;
chronon.run().await
}AWS performance study
What the AWS table measures
It shows the same completed-work rows as Resources: Embedded on SQLite and Remote fleet on its own stores, measured on AWS. A row appears only after a passing run. Scale-out was observed up to four application nodes.| Product | Workload | Profile | Completed work | p95 | Tested scale |
|---|---|---|---|---|---|
| Chronon | Due-job burst with a five-minute cohort | Embedded SQLite | 1.7 completed jobs/s | 84 s | 1 host |
| Chronon | Due-job burst with a five-minute cohort | Remote fleet | 2.4 completed jobs/s | 68 s | 4 worker hosts |
| Boson | Bounded job completion | Embedded SQLite | 117 completed jobs/s | not reported | 1 host |
| Boson | Bounded job completion | Remote fleet | 199 completed jobs/s | not reported | 4 worker hosts |
| Photon | Durable publish, one subscriber | Embedded SQLite | 100 completed publishes/s | 6.3 ms | 1 host |
| Photon | Durable publish, one subscriber | Remote fleet | 2,250 completed publishes/s | 1.7 ms | 4 app hosts |
| Photon | Durable publish, four-subscriber fanout | Embedded SQLite | 500 completed publishes/s | 6.0 ms | 1 host |
| Photon | Durable publish, four-subscriber fanout | Remote fleet | 3,250 completed publishes/s | 1.8 ms | 4 app hosts |
| Spectra | Durable write then read-your-write | Embedded SQLite | 80 completed writes/s | 4.3 ms | 1 host |
| Spectra | Durable write then read-your-write | Remote fleet | 100,000 completed writes/s | 36 s | 4 writer hosts |
| Valence | Hybrid lookup after a write | Embedded SQLite | 5,740 completed lookups/s | 7.8 ms | 1 host |
| Valence | Hybrid lookup after a write | Remote fleet | 17,715 completed lookups/s | 40 ms | 4 app hosts |
Embedded and Remote fleet
| Best for | Best for one or several small applications with a limited number of users. | Best for large deployments: many medium to large applications, or a large number of users. |
| Processes | One binary | 7+ services (see topology) |
| Databases | SQLite | Postgres, Redis, Fluvio, ClickHouse |
| Database isolation | One SQLite file per runtime, in one process | Its own database per runtime, each run as its own application |
| Admin apps | Valence, Boson, Chronon, Photon, Spectra, permissions, secrets, accounts, notifications | Same admin apps as Embedded, plus Nucleus |
| Deploy | One binary on any machine | AWS scripts, with Gluon running the applications and Docker containers |
| Automatic deployer | Not included | Planned |
| Availability | Public | Private preview |