open-standards/jouledesk/SPEC.md
Transaction Science 4759874771
All checks were successful
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 2m3s
standards workspaces build + test / aac-rs (pull_request) Successful in 1m42s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 46s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 33s
standards workspaces build + test / map-rs (pull_request) Successful in 29s
standards workspaces build + test / mesh-rs (pull_request) Successful in 34s
standards workspaces build + test / openpay (pull_request) Successful in 1m23s
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (pull_request) Successful in 1m1s
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 5s
no-vanity-metrics / WAI public text names no comparison (pull_request) Successful in 6s
no-vanity-metrics / WAI public text names no company or product (pull_request) Successful in 6s
standards workspaces build + test / arl-rs (pull_request) Successful in 1m14s
standards workspaces build + test / eoc-rs (pull_request) Successful in 2m0s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m39s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m11s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m12s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m18s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m13s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m20s
workflow hygiene / every workflow supersedes its own queue (pull_request) Successful in 5s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 4m2s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 4m38s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 7m8s
jouledesk, joulehook: the docs say a figure carries its meter's grade, not "measured"
After the branch graded these figures by how they were obtained, the
docs still called them measured: jouledesk's channel example printed
"the teammate's measured contribution", Joule::energy_summary's doc and
SPEC §6 said the contribution "is *measured*", the room example sealed
an Estimator figure and closed "at its measured energy" (each turn
"metered {est} µJ" for a scripted estimate), and joulehook INSTALL.md
promised the Mesh proxy as "the only *measured* + *capped* option" that
"returns the measured energy".

Each now says the figure carries the grade of the meter that produced it
(a hardware reading only where a live counter read the work, else an
estimate graded as one), that a rollup is no better than the weakest
figure it sums, and the room example calls its figures estimates.
Text only; jouledesk and jouledesk-github tests pass unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 18:10:28 -04:00

244 lines
13 KiB
Markdown

# Joule Desk — The Open, Energy-Accounted Agent Teammate
**Version:** 0.1.0-draft.1 · **Status:** Draft · **Profile:** `jouledesk/1`
**Specification text:** CC-BY-4.0 · **Reference code (`jouledesk-rs/`):** Apache-2.0
Joule Desk is the open standard for a **persistent agent teammate you delegate to in a
shared channel** — the shape a proprietary "tag @the-assistant in Slack" product made
familiar — built with the properties that shape needs and a closed product cannot
give you: authority that is a **signed, enforced grant** rather than an admin setting,
work that is **energy-metered and attested**, and a **shared, signed ledger the
whole channel can verify** rather than merely watch.
You add `@joule` to a channel. An administrator issues it a **grant chain** — the
tools and data it may touch, and a **joule budget**. Any member tags `@joule` to
delegate a task; it decides every action against those grants **outside the model**,
runs the work in an **attested sandbox**, **meters the energy**, and seals every
decision and every completed unit to the channel's ledger. Everyone in the channel
can not only see what it did — they can **verify** it: which principal, under which
capability, at what energy cost, with a signature that holds up.
Joule Desk is the **collaboration/teammate binding of [Joule Table](../jouletable)**
(`jt.transaction.science`) — the umbrella standard for a metered, gated, attested agent
at *every* surface; its sibling binding [Joule Hook](../joulehook) covers coding editors,
and Joule Desk's own `editor` class *is* Joule Hook. Joule Desk is one of the
[Transaction Science open standards](../README.md). It does not reinvent; it **composes**
the siblings — **JCP** (identity, grants, the shared channel, orchestration),
**`jcp-efficiency`** (the energy receipt), **Sandbox** (attested execution), and, where
the teammate works in an editor, **Joule Hook**.
---
## §1 Why Joule Desk exists
The agent-teammate shape is right: a persistent principal, tagged in a shared space,
that plans and executes delegated work under scoped access. But in its proprietary
form three things are weaker than the shape deserves:
- **Authority is configured, not enforced.** "These tools, this data, in this
channel" is an admin setting a relying party has to *trust*. Nothing outside the
model *decides* each action against a capability, and nothing *proves* afterward
what the agent was allowed to do.
- **The work is unmeasured.** When a teammate produces the majority of a team's
output, "did it work" is the wrong question; "what did it cost **per completed
unit**, and where is the waste" is the right one — and there is no energy figure.
- **The audit is visibility, not verifiability.** Everyone can *watch* the agent
work; no one can *verify*, later and independently, that a given action happened
under a given authority at a given cost.
Joule Desk closes all three: the authority is a JCP grant decided outside the model
and sealed; the work carries an `efficiency/1` receipt; the channel keeps a
signed ledger anyone holding the steward key can verify.
---
## §2 The teammate
`@joule` is a **persistent principal** — a stable `did:key` identity, not a session —
advertised by an **agent card** (§`jcp-a2a`) listing the skills it offers. The same
identity persists across tasks and across restarts, so its ledger is one continuous,
attributable chain. A deployment MAY run several teammates in a channel; each is a
distinct principal with its own card, grants, and ledger head.
---
## §3 The channel and its grants
A **channel** binds the teammate and its human **members** over a shared JCP channel
(§`jcp-channel`). It has:
- an **administrator** who issues the teammate a **grant chain** — a set of
[`SignedGrant`]s, each content-addressed to a `(surface, tool/skill)` audience and
carrying a **joule budget**;
- a set of **members** authorized to delegate;
- a **steward** who seals the ledger (§5) and whose public key verifies it.
The grant chain is the whole access model, and it is enforceable and portable: a tool
or datum the chain does not name is denied, whoever asks and however the request was
phrased. Reducing a teammate's authority is re-issuing (or revoking) grants, not
editing a console — and the change is itself a sealed, dated event.
---
## §4 The tag → the delegation loop
Tagging `@joule` with an intent submits a **task** (§`jcp-orchestrate`). For each task
the teammate, **in order**:
1. **Authorises** each action against its channel grants, in the runtime, never in
the model (JCP): the action's content-addressed resource MUST be permitted by a
held capability, and the grant's joule budget MUST cover the action's estimated
cost. A failure denies before any side effect.
2. **Executes** the admitted work in an **attested sandbox** (Sandbox S-tier), so
what ran is verifiable, not merely reported.
3. **Meters** the energy the work consumed (honest provenance).
4. **Seals** every dispatched decision — the allow, and any grant-level deny — and
every completed unit to the ledger (§5), debiting the budget on allow. (A tag the
teammate holds no skill or budget for is refused at routing; see §5.)
Retries are bounded and every attempt is charged (§`jcp-orchestrate`): a task that
never completes is spend the ledger attributes to no result, not silent loss.
---
## §5 The shared ledger
Every **dispatched** decision seals to the channel's ledger as an independently-signed
**JCR-1 receipt** — the allow that ran, and any grant-level deny. Alongside them the
ledger carries the **`efficiency/1`** receipt per completed unit (§6) and the **grant
events** (issuance, revocation) that change the teammate's authority. A tag for a skill
the teammate does not hold, or one with no remaining budget, is refused at **routing**
— enforced and recorded as a denied outcome before any dispatch; sealing that refusal
as a receipt too is a conformant extension.
The ledger is the multiplayer surface. Any member — and any third party holding the
steward's public key — can **verify** it receipt by receipt: that each is signed by the
steward, and therefore *which principal did what, under which capability, at what
energy cost, and in what order*. That is the difference from a product where the work
is merely visible: here it is **non-repudiable and independently checkable**. A
deployment MAY seal the ledger in the **chained** form (tamper-evident ordering) where
it wants the order itself — not only each entry — to be provable.
---
## §6 Energy accounting
Each task that runs seals an `efficiency/1` receipt (§`jcp-efficiency`) carrying its
energy at honest provenance and its outcome anchor (`completed`). Rolled up
(`aggregate`), a channel's ledger yields the figure a teammate's ROI actually turns
on — **joules per completed, verified unit** — which *charges the wasted energy of the
tasks that ran but never completed against the results actually delivered*. That is
the number a "tasks handled" count hides. Where a skill's work is itself token-based
(an LLM skill), the receipt also carries the per-token figures (µJ per accepted token,
tokens per completed unit, waste fraction); for a general task, joules-per-completed-
unit is the honest headline. The teammate's contribution is *metered*, not asserted:
each task's figure carries the grade of the meter that produced it — a hardware
reading only where a live counter read the task, otherwise an estimate, graded as
one — and a rollup is no better than the weakest figure it sums.
---
## §7 Settlement
The teammate's spend rides a **settle-able channel** (§`jcp-channel`): members and the
administrator exchange signed statements and settle, so the shared budget is
reconciled — who authorised what, what was spent, what remains — with an overdraft
that is bounded and enforced, not discovered on an invoice. A joule budget here is a
debited, settle-able quantity, the same object as the capability that spends it (JCP).
---
## §8 Host bindings (the collaboration surface)
Joule Desk is surface-agnostic. A **binding** maps a collaboration surface's primitives
onto the loop: "a member mentions `@joule`" → a task (§4), and the ledger (§5) → a
view the members can read and verify. Conformance profiles per surface:
| Profile | Surface | Tag | Ledger view |
|---|---|---|---|
| `chat` | a team chat (channels + mentions) | `@joule <intent>` | pinned/threaded receipts |
| `forge` | a git forge (issues/PRs) | `@joule` on an issue/PR | a checks/receipts view |
| `editor` | a coding editor via **JouleHook** | the editor's agent surface | JouleHook's receipt surface |
| `api` | a service | a task submission | the receipt log / MCP |
A binding MUST NOT weaken the loop: it maps the surface, it does not move the decision
into the model or drop the sealing.
The reference `jouledesk-bind` implements the `chat` profile for **Slack**, **Discord**,
and **Matrix**, and the `forge` profile for **GitHub** and **GitLab** (plus a neutral
`{who,text}` shape any other service maps onto), each as a thin event-parse +
reply-render pair; the `editor` profile is **JouleHook**. Parsing the event and
rendering the reply are pure and testable offline; *delivering* the reply is the
operator's token/webhook wiring.
### §8.1 The real-time (media) binding class
The bindings above are **discrete-message**: a mention becomes a task, and the reply
is a message. A `@joule` that joins a **live voice/video room** — Zoom, Google Meet,
Microsoft Teams, or a LiveKit/WebRTC room — is a different loop, because the work is a
continuous *session*, not one task per mention. A **real-time binding** is four seams:
1. **Join** the room under a signed grant (the JOIN seam). The room's own admission
credential — a LiveKit access token / `RoomAgentDispatch`, a Zoom RTMS handshake, a
Teams calling permission — is where the capability already lives; a conformant
binding *fuses it with the grant's joule ceiling* so nothing joins without authority
**and** budget.
2. **Gate each turn** outside the model (the TURN seam): a turn whose capability the
grant does not hold, or that would exceed the budget, is refused *before the model
generates* (in LiveKit, `on_user_turn_completed` → `StopResponse`), and the decision
seals.
3. **Meter each model call** at the model-call boundary (the METER seam): a `base_url`
proxy for a cascaded STT→LLM→TTS pipeline, a WebSocket relay for a native
speech-to-speech model, or the framework's own `gen_ai.usage.*` telemetry. Energy is
*derived* from token/audio counts at honest provenance — never claimed as a physical
measurement. (Media that flows peer-to-peer over WebRTC/SIP bypasses the meter; there
the binding gates at the token mint and reconciles from the provider's usage after.)
4. **Seal one `efficiency/1` receipt per session** (the RECEIPT seam), anchored to the
room/meeting id — the verifiable, energy-accounted record of what `@joule` did in the
call. A signed such receipt is a **superset of the compliance recording** these
platforms already sanction.
| Profile | Surface | Join seam | Meter seam |
|---|---|---|---|
| `room` (reference: **LiveKit**) | LiveKit / WebRTC room | access token + dispatch | `llm_node` override / OTel `gen_ai.usage` |
| `room` (**Zoom**) | Zoom RTMS + Meeting SDK | RTMS HMAC handshake + OAuth scope | RTMS socket / AI Studio tokens |
| `room` (**Teams**) | Graph Cloud Comms media bot | `Calls.AccessMedia` + RSC | per media-frame + STT/LLM |
The reference `RealtimeSession` (`jouledesk-rs`) models the four seams; its METER seam
reuses the *same* model-call proxy that meters a text session, so a joule ceiling is
enforced identically whether `@joule` is typing or talking.
---
## §9 What Joule Desk adds over a closed teammate
| Property | Closed teammate | Joule Desk |
|---|---|---|
| Authority | admin configuration, trusted | a **signed grant**, decided outside the model, enforced |
| Access change | a console edit | a **sealed, dated grant event** |
| Work integrity | reported | **attested** (Sandbox) |
| Energy | none | **`efficiency/1`** — µJ + cost per completed unit + waste |
| Audit | visible | **verifiable** — a signed ledger anyone can check |
| Budget | a quota | a **debited, settle-able** joule budget (§7) |
| Portability | one product | **any surface**, one standard (§8) |
| Openness | proprietary | **forkable** — the wire and the right to fork are public |
---
## §10 Relationship to the sibling standards
Joule Desk is a **profile that composes**, not a re-implementation:
- **JCP** supplies identity (`Did`), the grant model, the shared **channel**
(`jcp-channel`), and **orchestration** (`jcp-orchestrate`); Joule Desk binds them to
the teammate-in-a-channel shape and the tag→delegate loop.
- **`jcp-a2a`** supplies the teammate's advertised **agent card** and budget mandate.
- **`jcp-efficiency`** is the energy receipt the ledger carries per completed unit.
- **Sandbox** is where admitted work runs, attested.
- **JouleHook** is the `editor` binding — when the teammate works in a coding editor,
its tool calls ride JouleHook's gate + meter + receipt seams.
The contribution of Joule Desk is the **normative teammate-in-a-channel profile** — the
persistent principal, the channel grant chain, the tag→delegate→attest→meter→seal
loop, and the shared verifiable ledger — that turns a pile of primitives into an
accountable, energy-native teammate anyone can run and verify.