# Gadgets design: Ring 0–3

Impo treats gadgets as capabilities of a personal agent and as sources of events.
People should also be able to create small, persistent gadget agents in natural
language: “When I pick it up in the morning, read my first meeting.” The platform
hosts those agents and controls their access to hardware, tools and data.

Status as of 2026-10-09: account-owned gadget commands and events exist. The
user-created gadget-agent runtime described here is a proposal. This document
records the system design; it does not announce that runtime as available.

## Origin and source of truth

The starting point is the SDK's [Gadget agents proposal](https://github.com/impoai/impo-gadget-sdk/blob/6048a04ad796f0e51a50cc2c36e3c9131519e65d/docs/GADGET-AGENTS.md),
written from the 2026-10-09 design discussion. This document connects that proposal
to Impo's API, workers, clients and current implementation. The SDK owns board
interfaces, firmware and the [capability vocabulary](https://github.com/impoai/impo-gadget-sdk/blob/6048a04ad796f0e51a50cc2c36e3c9131519e65d/CAPABILITIES.md).

Dreamer's influence comes from David Singleton's [Latent Space interview](https://www.latent.space/p/dreamer)
(2026-03-20). Relevant sections:

| Time | Principle discussed |
| --- | --- |
| 15:32–17:46 | Discover available tools, plan, build, test, then host the result. |
| 21:55–23:23 | Sidekick mediates cooperation and permissions; the operating-system kernel and rings are the analogy. |
| 44:08–45:31 | Triggers start agents; the platform supplies activity logs and a database per agent, with user ownership. |
| 45:53–47:19 | Agents expose callable functions; the platform supplies identity and data isolation. |

**The four numbered rings below are Impo's adaptation.** The interview does not
define this hardware stack or these Ring 0–3 assignments. Hardware events,
device arbitration and physical-action permissions are our extension of the
model.

## The four rings

Rings describe responsibility and authority. They are architectural boundaries,
not CPU privilege levels or four processes that must run on one machine.

| Ring | Role | What belongs here | Who changes it |
| --- | --- | --- | --- |
| **0 — Kernel** | Own policy and coordinate execution. | Impo's personal agent, API, durable workers, dispatcher and gadget gateway. Account ownership, tool admission, model routing, memory access, budgets and device arbitration. | Platform maintainers. Users configure exposed preferences and grants. Generated agents cannot change enforcement. |
| **1 — Gadget agents** | Run a person's persistent behavior. | Gadget bindings, triggers, allowed actions, instructions, bounded state and run history. `rules` for fixed actions; `llm` for work that requires judgement. | Users through their personal agent; later, builders through the same validated API or CLI. |
| **2 — Devices** | Expose and execute hardware capabilities. | Board adapters, shared firmware or Linux runtime, registered commands, capability summaries and events. | Makers adapt boards; SDK maintainers own shared runtime and vocabulary. |
| **3 — Ecosystem** | Integrate other devices and services. | Product-specific skills and adapters, including the proposed route to home-network devices through a gadget tunnel. | Integration authors and tool builders, within platform policy. |

**Ring 1 requests actions from Ring 0. It never receives direct device or gateway
admin access.** The same rule applies when one gadget agent invokes another.
Ring 3 integrations also require Ring 0 authorization; a skill cannot grant it.

“Through the kernel” means through server-enforced policy. It does not require
an extra main-chat model turn for every action. The personal agent builds and
manages behavior; the API and worker enforce its execution limits.

```mermaid
flowchart LR
    User["User / native or Web client"] --> Main["Ring 0: personal agent"]
    Main -->|"create or revise — proposed"| Agents["Ring 1: gadget agents"]
    Agents -->|"request allowed action"| Policy["Ring 0: policy + worker + dispatcher"]
    Main -->|"existing gadget tool call"| Policy
    Policy --> Gateway["Ring 0: gadget gateway"]
    Gateway -->|"link.invoke"| Device["Ring 2: firmware + board"]
    Device -->|"link.event"| Gateway
    Gateway -->|"proposed event admission"| Router["Ring 0: trigger router"]
    Router -->|"match and enqueue"| Agents
    Router -->|"no matching agent"| Main
    Policy -.->|"future controlled integration"| Ecosystem["Ring 3: skills + third-party devices"]
```

The SDK's boards / capabilities / ecosystem organization and the deployment's
app / API / worker / gateway split remain useful views. They answer where code
lives. The rings answer who owns policy and what others may extend.

## What people can customize

| Need | Extension point | Boundary |
| --- | --- | --- |
| Add a board | Implement the SDK board interface and build configuration; add drivers where needed. | A board advertises only capabilities it implements. Shared networking, pairing and audio code stay in the runtime. |
| Add a hardware operation | Register a board command with its description, parameters and result. Promote reusable operations into the shared capability contract. | A command description teaches the personal agent how to call it; it cannot change server permissions. |
| Change one user's gadget behavior | Create or revise a Ring 1 definition. | Proposed. Users do not need to fork firmware or edit the global personal-agent prompt. |
| Integrate another product | Add a Ring 3 skill or adapter against supported platform tools. | Instructions alone do not implement a transport or make a device reachable. |
| Change routing, models or authorization | Change Ring 0 through the platform's normal implementation and release process. | These choices are not delegated to generated gadget agents. |

## How a gadget agent starts

A gadget agent is a saved executable definition. Its prompt describes behavior;
its tool allowlist describes available operations; its trigger registration
determines when it runs. A skill can teach the builder to create it, but is not
the scheduler or event router.

The proposed authoring flow is:

1. The user describes the behavior in Chat. The personal agent inspects
   `impo_list_gadgets` and available platform tools, then forms a plan using
   capabilities that actually exist.
2. A proposed creation tool, `impo_create_gadget_agent`, submits the definition.
   The server derives its owner from authenticated context and validates gadget
   bindings, triggers, command names, parameter shapes, grants and budgets.
3. A dry run reports the matched trigger and intended actions without touching
   hardware. A requested live trial uses the same policy and dispatch path.
4. The saved definition can be enabled, disabled, edited and inspected from the
   gadget's automations view. This view and the creation tool are not built yet.
5. Once enabled, a matching event, schedule or explicit invocation admits a run.
   The app does not need to remain open, and the user does not repeat the prompt.

The proposal's definition includes gadget bindings, triggers and filters,
allowed commands and tools, physical-action permission, budgets, instructions,
execution kind, state and enabled status. Its sample JSON is illustrative, not
a versioned API contract. A `rules` definition must also contain validated
actions; prose instructions alone cannot make a deterministic rule executable.

Two examples explain the execution choice:

- “When shaken, play this sound”: a `rules` run dispatches a fixed
  `speaker.play_url` action. It needs no model call, but still uses hosting,
  transport and policy checks.
- “When picked up in the morning, read my first meeting”: an `llm` run uses
  specifically granted calendar access and `speaker.say`. It runs in a bounded
  Rebyte Agent session on the worker. Calendar access must come from an available
  platform tool; unattended runs cannot assume a foreground phone is available.

## Runtime and policy

Today, the gateway converts `link.event` into a `[Gadget event]` main-chat message
and sends the resulting spoken reply to that gadget. The proposed router would
admit a structured event at `POST /api/v1/gadgets/events`, match enabled gadget
agents and queue their runs. An event with no matching agent retains the current
main-chat behavior. A matched but rate-limited or failed run must not silently
bypass its limits by falling back to main Chat.

Schedules use Temporal to admit ordinary runs. Scheduling and execution remain
separate, as in [scheduled tasks](../contracts/scheduled-tasks.md). Model work
stays on the durable worker using `@rebyteai/agent-sdk` and
`client.beta.agents`; the event handler does not run a model. A future observation
worker could turn camera frames into semantic events. Continuous observation
and `camera.watch` are not current capabilities.

The target Ring 0 policy must cover:

- **Ownership and grants:** bind each definition, event, run, state update and
  command to its account. Check the current gadget pairing and registered
  command at execution. A stored spec or generated prompt cannot grant itself
  camera, movement, connector or memory access.
- **Revocation:** disabling an agent, removing a grant or unpairing a gadget
  prevents future dispatch. Revision checks fence work queued under old policy.
- **Budgets:** bound run frequency, cooldown, duration, tool calls and model
  usage. Event payloads and command descriptions are input data, not authority.
- **Arbitration:** give the person's active interaction priority over background
  speech, serialize speaker use and discard stale queued speech. Physical
  actions need an explicit grant and bounded execution. Firmware keeps local
  stop and hardware limits even if the network fails.
- **Recovery:** deduplicate admitted triggers and retain action receipts. An
  uncertain physical or audible side effect is not retried automatically. The
  existing `impo_gadget_command` already declares `retry: 'never'`.
- **State and visibility:** keep state and logs scoped to the owner and agent;
  prevent overlapping runs from overwriting state. Report an accepted playback
  request separately from completed playback or verified physical movement.

These per-agent controls are requirements for Ring 1, not claims about the
current dispatcher. The SDK proposal starts with bounded JSON state (64 KB) and
separate definition/run records. A dedicated per-agent database is a later
option. Impo's first implementation would use its existing Drizzle repository
boundary rather than introduce a second database system just to match Dreamer.

## Current implementation and gaps

| Area | Present implementation | Still proposed |
| --- | --- | --- |
| Ring 0 command path | `impo_list_gadgets` and `impo_gadget_command`; owner comes from the durable invocation. Registered command and online checks; privileged commands withheld. | Per-agent grants, budgets and shared device arbitration. |
| Ring 1 | Ordinary Tasks and scheduled Tasks already provide durable work, but are not saved gadget-agent definitions. | Definition/run storage, creation tools, structured event admission, trigger matching, rules executor, bounded LLM runs and automation UI. |
| Ring 2 | SDK board adapters, `commands_v2`, `capabilities`, `link.invoke` / `link.result`, and `link.event`. Availability depends on the board. | Continuous observation; any unimplemented board capability. |
| Ring 3 | Product-specific guides exist in the SDK's `skills/`. | The Impo gateway's `/link-tunnel` transport and a permissioned execution path for these integrations. The guides do not establish working end-to-end support. |
| Clients | iOS and Android provide gadget setup and management. Web consumes the shared Impo API. | Gadget-agent controls on clients; Web cannot assume native BLE setup. See the [Web guide](../web/README.md). |

Implementation references:

- [Gadget tools](../server/src/tools/gadget-tools.ts): discovery, instructions,
  command checks, dispatch and photo results.
- [Server gateway adapter](../server/src/gadgets/gateway.ts): account routes,
  registered capabilities, pairing and command restrictions.
- [Gateway device hub](../server/gadget-gateway/device-hub.mjs): device
  registration, command delivery, events and spoken replies.
- [API routes](../server/src/http/api-server.ts): authenticated client routes and
  the gateway service credential's narrow route allowlist. The proposed event
  endpoint is not currently in that allowlist.
- [Gateway guide](../server/gadget-gateway/README.md): transport and operations.

## Delivery sequence

1. **Rules foundation:** specify the versioned definition and event contracts;
   implement owned storage, durable event admission, trigger matching, policy
   checks and a fixed-action executor. Add creation/edit/disable tools, dry runs
   and client controls. Retain unmatched-event behavior.
2. **Bounded LLM agents:** add worker sessions, allowlisted platform tools,
   resource arbitration and useful run inspection. Reuse the same policy path.
3. **Observation:** define capture consent, frame retention, streaming limits
   and a perception worker before adding camera-derived triggers.
4. **Sharing and ecosystem:** share definitions without credentials, user state
   or inherited grants. Add supported integrations and transport explicitly.

Before phase one ships, verification must cover ownership rejection, duplicated
events, grant revocation, disabled or revised definitions, offline gadgets,
unknown command outcomes, overlapping runs and recovery after worker restart.
Dry runs must have no hardware effects. Simulator and fixture checks must be
followed by physical-device checks for speech, sensor events and any enabled
movement.

Exact event envelopes, action schemas, concurrency policy, quiet-hour settings
and client layout remain implementation decisions. Record them in executable
contracts when phase one starts; the ring boundaries above should remain stable.
