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

One product shell

Signed-in applications share Orbital chrome, an app directory, workspace search, notifications, appearance controls, and help. Each product can add routes and utilities without rebuilding the shell.
Every admin app in one launcher, behind one sign-in.

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
Sign-in, two-factor and 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
Check which fields the signed-in user can read or write on a real record.

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
The counter demo updates in every open tab as soon as someone clicks.

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.
ProductWorkloadProfileCompleted workp95Tested scale
ChrononDue-job burst with a five-minute cohortEmbedded SQLite1.7 completed jobs/s84 s1 host
ChrononDue-job burst with a five-minute cohortRemote fleet2.4 completed jobs/s68 s4 worker hosts
BosonBounded job completionEmbedded SQLite117 completed jobs/snot reported1 host
BosonBounded job completionRemote fleet199 completed jobs/snot reported4 worker hosts
PhotonDurable publish, one subscriberEmbedded SQLite100 completed publishes/s6.3 ms1 host
PhotonDurable publish, one subscriberRemote fleet2,250 completed publishes/s1.7 ms4 app hosts
PhotonDurable publish, four-subscriber fanoutEmbedded SQLite500 completed publishes/s6.0 ms1 host
PhotonDurable publish, four-subscriber fanoutRemote fleet3,250 completed publishes/s1.8 ms4 app hosts
SpectraDurable write then read-your-writeEmbedded SQLite80 completed writes/s4.3 ms1 host
SpectraDurable write then read-your-writeRemote fleet100,000 completed writes/s36 s4 writer hosts
ValenceHybrid lookup after a writeEmbedded SQLite5,740 completed lookups/s7.8 ms1 host
ValenceHybrid lookup after a writeRemote fleet17,715 completed lookups/s40 ms4 app hosts

Embedded and Remote fleet

Best forBest 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.
ProcessesOne binary7+ services (see topology)
DatabasesSQLitePostgres, Redis, Fluvio, ClickHouse
Database isolationOne SQLite file per runtime, in one processIts own database per runtime, each run as its own application
Admin appsValence, Boson, Chronon, Photon, Spectra, permissions, secrets, accounts, notificationsSame admin apps as Embedded, plus Nucleus
DeployOne binary on any machineAWS scripts, with Gluon running the applications and Docker containers
Automatic deployerNot includedPlanned
AvailabilityPublicPrivate preview