Tiers and Priority

CUST/OS provider configuration has two fields that look superficially similar but answer fundamentally different questions:

  • taskPriority -- "In what order should I try the providers I have?"
  • tier -- "What kind of trust and reachability environment is this provider in?"

The two questions are orthogonal

taskPriority is ordinal. It is a sortable per-provider integer that determines fallback order: given the providers that are healthy right now, which one should the runtime try first?

tier is categorical. It is a label from a fixed set of operationally meaningful environments, and it answers a structural question that priority cannot: what kind of compute is this, where is it physically and politically, and what trust expectations does it carry?

You can have:

  • Two providers in the same tier with different priorities (e.g., two cloud LLMs you want to fail over between).
  • Two providers in different tiers with overlapping priorities (e.g., a handheld provider at priority 1 and a cloud provider at priority 5).
  • A single provider whose tier matters even when there is only one option (e.g., a single handheld LLM whose tier label drives EMCON lockdown without changing any priority math).

Priority cannot express any of those facts on its own. It is a one-dimensional sort. Categorical knowledge -- "is this thing local? is it on the mesh? is it in the cloud?" -- has to live in tier.

The six tiers

Tier What lives here Trust posture Latency expectation
handheld The operator's own device. Native servers running locally on the same hardware. Full operator trust. No network involved. Tens to hundreds of milliseconds.
pack On-person compute connected via wired link (USB, Ethernet). Physically carried by the operator. No RF emissions. Examples: Jetson Nano in a ruck via USB tether, Raspberry Pi in a chest rig via Ethernet adapter. Full operator trust. Wired connection, no RF signature. Tens to hundreds of milliseconds.
mobile A small companion compute device the squad carries -- tactical edge brick, buddy compute pack, kit server. Squad-level trust. Inside the squad's perimeter. Hundreds of milliseconds.
mounted A vehicle-mounted compute platform with real cooling, power, and GPU. Vehicle-crew trust. Mobile with the unit but not handheld. Hundreds of ms when in range; gone when dismounted.
command-post A back-line workstation reachable over the TAK mesh. Runs its own CUST/OS node, accepts delegated inference requests. Cross-trust-boundary. Each side stays in its own boundary while sharing reasoning. Seconds (mesh round-trip).
cloud An internet-hosted provider. Someone else's network, infrastructure, jurisdiction. Lowest trust. Bound by classification and operator clearance. Seconds, contingent on network availability.

The tiers are roughly ordered from closest/most trusted to furthest/least trusted.

Security modes (lockdown)

The security.mode field selects a lockdown mode that filters which tiers are allowed:

Mode Allowed tiers Use it for
normal handheld, pack, mobile, mounted, command-post, cloud Default -- everything in your config is in play
no-cloud handheld, pack, mobile, mounted, command-post Skip cloud providers
field-only handheld, pack, mobile, mounted Deployed in the field with vehicle-mounted and local edge compute, but no command post or cloud connectivity
squad-only handheld, pack, mobile Squad-internal compute only
emcon handheld, pack Operator-only operation; no wireless, no mesh, no cloud. Wired pack peripherals are still trusted.
standalone handheld Device-only operation. No external compute trusted -- not even wired peripherals. For compromised environments or when no peripheral can be trusted.

This filter applies uniformly to all inference paths: chat, embedding, transcription, TTS, and vision. There is no bypass.

The NavBar carries a security mode button that lets the operator switch modes with a single tap (e.g., "enter EMCON now") without editing the config file.

What tier drives beyond lockdown

Classification ceilings

Providers without an explicit classification field default to UNCLASSIFIED for the cloud tier (fail-safe) and to the operator's clearance level for everything else. Forgetting to set classification on a cloud provider is safe by default.

Per-tier budget defaults

defaults:
  byTier:
    handheld:
      requestTimeoutMs: 30000
      maxTokens: 1024
    cloud:
      requestTimeoutMs: 120000
      maxTokens: 4096

Per-provider values still win. Tier values fill in where providers do not specify their own.

Tier-aware hooks

Hook rules can target specific tiers:

hooks:
  rules:
    - event: PreToolUse
      toolPattern: "send_*"
      whenTier: ["cloud", "command-post"]
      action: require_approval
      reason: "Comms tools require approval when reasoning at remote tiers"

This fires only when the active inference provider is in the cloud or command-post tier.

Fallback grouping

agent.fallbackMode controls how providers are ordered:

  • priority (default) -- flat sort by taskPriority.
  • tier-grouped -- sort by tier order (handheld, pack, mobile, mounted, command-post, cloud) first, then by taskPriority within each tier. The entire handheld tier is tried before any pack provider.

Delegation gating

Standalone, EMCON, squad-only, and field-only modes implicitly disable cross-device delegation because they exclude command-post from the allowed tier set.

Voice pipeline

Voice (STT / TTS) uses the same router as every other task, which means the same tier filter the active security mode applies. If you're on emcon and only handheld + pack are allowed, a cloud STT provider is skipped — not because voice is special, but because the security mode filters it out along with everything else. Operators who want cloud-backed STT/TTS configure those providers normally and pick an appropriate security mode at run time.

Audit

Every inference request is logged with its tier. The Audit panel's "By Tier" view shows call counts and token totals grouped by tier, so operators can see how much reasoning happened at each level.

How tier and priority compose

A representative config:

agent:
  fallbackMode: tier-grouped

security:
  mode: emcon

providers:
  - name: "local"
    tier: "handheld"
    taskPriority: 1
  - name: "ruck-jetson"
    tier: "pack"
    taskPriority: 3
  - name: "lan"
    tier: "mobile"
    taskPriority: 5
  - name: "vehicle"
    tier: "mounted"
    taskPriority: 10
  - name: "cp"
    tier: "command-post"
    taskPriority: 50
  - name: "claude"
    tier: "cloud"
    taskPriority: 100

What happens on each call:

  1. Tier filter runs first. mode: emcon removes everything except handheld and pack. Only local and ruck-jetson are in the running.
  2. Sort orders the survivors by tier-grouped order (handheld first, then pack).
  3. Health check decides whether local is callable.
  4. Classification boundary clamps which providers can see the operator's data.
  5. Hook rules are evaluated -- whenTier matches do not fire because we are at handheld or pack, not cloud or command-post.
  6. The call goes out.

Flip mode: emcon to mode: normal and the whole config lights up: tier filter keeps everything, tier-grouped sort orders by proximity, and hooks fire when reasoning moves to remote tiers.

How to set tier correctly

Set it based on the provider's physical and trust environment, not on what you wish it were:

  • A file:// URL pointing at a model on the device is handheld.
  • An http:// URL pointing at a wired peripheral the operator carries on their body (USB-tethered Jetson, Ethernet-connected Pi in a chest rig) is pack.
  • An http:// URL pointing at a companion device the squad carries is mobile.
  • An http:// URL pointing at a vehicle compute platform is mounted.
  • A cot:// URL or any provider reachable over the TAK mesh is command-post.
  • An https:// URL pointing at someone else's data center is cloud.

When in doubt: "If the operator went standalone, would I want this provider to keep working?" If yes, it is handheld. "If the operator went EMCON, would I want this provider to keep working?" If yes, it is handheld or pack. If no, classify it by where it actually lives.

See also