01 Product¶
Status: draft M0. Terms: 00-glossary.md. Data: 03-data-model.md. Sync and offline: 04-sync-protocol.md. Permissions and actions: 05-actions.md, 07-permissions.md. Agents: 09-agents.md, 10-backend-policy.md. Push: 13-push-notifications.md. Apps, technical: 15-client-architecture.md. Terminal: 24-terminal.md. Visualization: 25-visualization.md. Design: docs/design/.
This chapter describes what people see and operate. It does not define permissions; every operation names the action from the action catalogue that the server checks. The app shows only what the server allows and contains no permission logic of its own.
1. Vision¶
Bothy is a command center for AI agents in chat form: chat, live view, grants, terminal, costs and statistics in one self-hosted, open-source app. Agents are Hermes Agent, Claude Code and others that connect through the public API.
- Chat like Discord. Structure and operation like Discord; AI agents are full participants.
- Live view. Every thread is an agent session: you see the agent working (live box with tool and status lines), answer its questions and approve actions with a button.
- Grants. Every person sees and controls only what has been granted to them; the server checks this on every access (07-permissions.md).
- Terminal. A real shell or an interactive Claude Code session on a connected host, in the desktop app, on the phone and in the web console. Security is built in and cannot be turned off: a separate permission per host, confirmation on every opening, an end-to-end encrypted stream, audit, idle timeout (24-terminal.md).
- Costs. Every agent shows what it runs on (personal subscription or organization key), and in organization mode what a run, a thread, a space costs (10-backend-policy.md).
- Statistics. Own, native visualizations in apps and console: live topology of the runs, backend view, delivery live, executive page, playable timeline, TV mode; for operations the same views as a Grafana panel plugin (25-visualization.md).
- Own instance. An instance belongs to one organization and runs on its own hardware or in its own cloud. Hermes Agent is one agent framework among several, not the core.
- Showcase standard. What people see (apps, console, Grafana plugin, README, docs site, release pages) should be clear to a person within one minute at first sight. Images and video come from a demo instance with invented data (PLAN, milestone M7).
2. Personas¶
Described neutrally; the names are examples. Roles are templates for grants, not a separate kind of permission (Baseline section 3).
| Persona | Goal | Typical tasks | Devices | Grants (example) |
|---|---|---|---|---|
| Owner (Alex) | Work with agents and lead the instance in terms of content | Chats with agents in all spaces, give grants, configure agents and backend policy, keep an eye on costs, read the audit; on the go, open a terminal on their own host from the iPhone; live topology and executive page | Desktop (Mac or Windows), iPhone | Owner: everything except other people's direct messages; terminal on every host, unless I6 blocks it (24-terminal.md, section 7) |
| Deputy (Sam) | Operate granted spaces day to day | Trigger agents in the Support space, answer questions, review drafts; approve actions only if the capability has been given | iPhone, Android, laptop | trigger on the Support space, plus upload; no approve_actions; no terminal |
| Developer (Robin) | Work on code with a runner agent | Posts in dev forums, read tool output, stop runs, watch costs and context, resume sessions; in the terminal on her own host, use claude interactively |
Desktop with keyboard | trigger on a dev forum with project binding; grant terminal only on the host assigned to her (SR10); for isolation see 21-dev-isolation.md |
| Instance operator | Install the instance and keep it running | Compose installation, login providers, backup, updates, status page, monitoring; pair hosts and declare the LLM login; Grafana with the panel plugin; TV mode in the office | Web console, command line, Grafana | Owner or a separate person with the owner role; not to be confused with the operator agent (operator) |
| Bot developer | Connect an agent or an app | Build an adapter or app with the SDK, write the manifest, request a token from the owner, test webhooks | Own environment, web console of the owner | App or agent principal with scopes; at most write (R-DM-08) |
3. Feature list¶
Column "Milestone": core = content of a build milestone (the plan defines the order), later = wanted, but after the core milestones, never = deliberately excluded, with a reason. Column "Where": D = desktop (macOS, Windows), M = mobile (iOS, Android), W = web console. Where a feature of the addendum of 2026-10-10 is built in several milestones, the remark names the build milestones from the plan.
3.1 Structure and conversations¶
| Feature | Milestone | Where | Action(s) | Remark |
|---|---|---|---|---|
| Spaces collapsible, personal order, across devices | core | D, M | sidebar.update |
global order only through administration (space.reorder) |
| Text channels with main thread and threads from messages | core | D, M | thread.create, message.create |
|
| Forum channels with a dense post list, tags, Done section | core | D, M | thread.create, thread.tags.set |
list instead of cards (study B) |
| Dev forum with project binding and runner agent | core | D, M | channel.project.bind |
triggering only with project_bindings.ready |
| Button "New post" or "New chat" | core | D, M | thread.create |
replaces the detour through a helper channel |
| Fixed thread ID, auto title with source, edit title | core | D, M | thread.title.update |
a manual title is never overwritten automatically |
| Set Done, a new message reopens | core | D, M | thread.close, thread.reopen |
section 6.1 |
| Move a thread (only channels with the same operator) | core | D | thread.move |
the dialog shows only valid targets |
| Direct messages between people | later | D, M | dm.create |
switch dm.enabled; without an agent |
| Threads in threads | never | one level is enough; deeper trees fragment agent sessions | ||
| Voice and video channels, screen sharing | never | not core to the product; large operational effort (Baseline 4) | ||
| Multiple servers, server bar, public invite links | never | one instance is one organization (B13); outsiders join only when the owner creates them | ||
| Role hierarchy like Discord | never | grants with levels and capabilities replace roles (ADR 0018) |
3.2 Agents¶
| Feature | Milestone | Where | Action(s) | Remark |
|---|---|---|---|---|
| Operator per channel visible in the channel header | core | D, M | channel.read |
without an operator it says "No agent answers here" |
| Live box running, pinned, with stop | core | D, M | run.read, run.cancel |
section 6.2 |
| Live box collapsed after the end, expandable | core | D, M | run.read |
|
| Trigger state as icons on the message | core | D, M | replaces status emoji (section 6.3) | |
| Follow-ups during a run | core | D, M | run.followup.create |
|
| Buttons, selects, forms on messages | core | D, M | interaction.create |
once, only for those authorized |
| Slash commands with suggestions and options | core | D, M | command.invoke, command.autocomplete |
control commands (/stop) never go to the model |
| One agent session per thread, earlier sessions, start over, resume | core | D, M | agent_session.reset, agent_session.bind |
|
| Backend policy badge in the thread header and on the agent card | core | D, M, W | agent.read |
Personal or Organization |
| Costs per run and thread (organization: estimate until reconciliation) | core | D, M | cost.read.thread |
with Personal only information |
| Overview "Running now" | core | D, M | run.overview.read |
as live cards or list (D10, M11; addendum of 2026-10-24) |
| Run graph: agent, subagents, workflows and background jobs as a tree on a time axis, live | core | D, M | run.read |
D14, M12; addendum of 2026-10-24; not in the web console (no chat, ADR 0028) |
| Typing indicator (people); the agent "types" through the live box | core | D, M | typing.start |
|
| Presence of agents (online, degraded, offline) | core | D, M | agent.read |
people have no presence |
| Presence of people ("online") | never | reveals working hours; privacy and co-determination (study C, R5) |
3.3 Messages¶
| Feature | Milestone | Where | Action(s) | Remark |
|---|---|---|---|---|
| Markdown, code blocks, long answers without splitting, collapsed with "Show more" | core | D, M | message.create |
limit message.max_content_bytes |
| Edit and delete own messages, view versions | core | D, M | message.update, message.delete, message.revisions.read |
no editing deadline |
| Reply with quote | core | D, M | message.create |
|
| Reactions with a free Unicode character | core | D, M | reaction.add |
status is not a reaction |
| Mentions of people and agents | core | D, M | message.create |
suggestions only from what is visible |
| @everyone, @here, role mention | never | noise; notification per channel is enough | ||
| Pin (moderation) | core | D, M | pin.create |
needs manage |
| Templates (personal and per channel) | core | D, M | template.read, template.manage |
|
| Drafts across devices | core | D, M | draft.write |
notice when a newer version was overwritten |
| Read receipts of other people | never | performance monitoring; the read state stays personal (ruling R-PR-03) | ||
| Polls, widgets, to-do lists in text | never | agents deliver forms through components | ||
| Stickers, GIF search, profile decorations, banners | never | distraction, license questions (Baseline 4) | ||
| Link preview from the server | never | the server loads no foreign URLs (SSRF) | ||
| Link preview in the client | later | D, M | only after opt-in per person, because the app then contacts foreign servers |
3.4 Files and voice¶
| Feature | Milestone | Where | Action(s) | Remark |
|---|---|---|---|---|
| Files and images with preview, in and out | core | D, M | file.upload, file.read |
served only after the scan |
| iPhone: photo, camera, file | core | M | file.upload |
|
| Record a voice message, play it, transcript | core | D, M | file.upload, file.transcribe |
switch voice.enabled; AAC (15-client-architecture.md) |
| Share from other apps into a chosen target | core | M, macOS | message.create, file.upload |
Windows see the next row |
| Share from other apps on Windows | later | D | needs MSIX identity; after the first Windows release | |
| Export of a channel | core | D, W | export.channel |
capability export, step-up |
3.5 Notification, search, navigation¶
| Feature | Milestone | Where | Action(s) | Remark |
|---|---|---|---|---|
| Unread counter, mention counter | core | D, M | from read_states and mentions |
|
| View "Mentions" | core | D, M | mention.list |
|
| Notification per space, channel, thread (all, mentions, mute), quiet hours | core | D, M | notification_pref.update, quiet_hours.update |
section 10 |
| Push without content; the app fetches the text | core | M, macOS | push.register |
Windows: notification area with its own connection |
| Push through the Windows service (WNS) | later | D | without a running app no notification; Baseline R-Push | |
| Email notifications | never | content does not belong in mailboxes (Baseline 4) | ||
| Full-text search with permission filter | core | D, M | search.query |
hits only from what is visible |
| Quick switcher Cmd/Ctrl+K | core | D | on mobile as a search field at the top | |
| Keyboard shortcuts | core | D | section 7 | |
| Multiple windows, thread as its own window | later | D | multi-window in Flutter still experimental (15-client-architecture.md) | |
| iPad layout with columns | later | M | until then the scaled iPhone layout |
3.6 Offline, sync, devices¶
| Feature | Milestone | Where | Action(s) | Remark |
|---|---|---|---|---|
| Read offline (recently opened threads) | core | D, M | cache according to 04 section 13 | |
| Send offline with a queue, states visible | core | D, M | section 6.6 | |
| Read state, drafts, settings, sidebar in sync | core | D, M | ||
| Approve, revoke a device; end sessions | core | D, M, W | device.approve, device.revoke, session.revoke |
new devices wait |
| End-to-end encryption of chat content | never | agents must read (Baseline 4); the terminal stream, by contrast, is end-to-end encrypted (3.8) | ||
| Chat in the browser | never | web only for the console (ADR 0028) |
3.7 Administration, operations, integration¶
| Feature | Milestone | Where | Action(s) | Remark |
|---|---|---|---|---|
| Create, disable people; groups | core | D, W | user.create, user.disable, group.* |
no self-registration |
| Grant wizard with plain-language preview and I1 check | core | D, W | grant.create |
step-up |
| "Who has access?" with origin | core | D, W | access.explain |
|
| "View as person" (read only) | core | D, W | access.view_as |
logged |
| Agents: backend switch, costs, tokens, commands | core | D, W | agent.billing_mode.set, cost.read.aggregate, token.create |
|
| Filter the audit, verify the chain | core | D, W | audit.read, audit.verify |
|
| Statistics | core | D, W | stats.read |
|
| Live topology of the agent runs, backend view, delivery and sync live, playable daily timeline | core | D, M, W | stats.read, cost.read.aggregate |
own measurement, no values per person; 25-visualization.md; mobile screen M10; build: visualization track after the early M4 tickets against fixtures, server and apps M6 |
| Executive page with SLO traffic light "own measurement" | core | D, M, W | stats.read, cost.read.aggregate |
traffic light only for owners; build M6 |
| TV mode (full screen, dark, rotating views) | core | D, W | stats.read |
costs hidden by default; build M6; screen D13 |
| Grafana panel plugin "Bothy Live" for operations | core | Grafana | none (permissions of Grafana) | build M7; unsigned locally until V1, signature later |
| Embed Grafana dashboards in apps | never | only optionally in the web console, off by default (ADR 0069) | ||
| Status page | core | D, M, W | status.read |
public only with status.public_enabled |
| Import from Discord | core | W | import.manage |
22-import-migration.md |
| Install apps, webhooks | core | W | app.install, webhook_out.manage, webhook_in.create |
|
| Emergency actions on the phone: revoke a device, revoke a grant, disable a person, stop a run | core | M | device.revoke, grant.revoke, user.disable, run.cancel |
large flows (create a grant, audit, statistics) only on desktop and web |
| Marketplace for bots | never | the owner installs apps deliberately; no catalogue of third-party providers |
3.8 Terminal¶
Normative: 24-terminal.md. Build: server and host service M2, desktop M4, mobile M5, web console M6.
| Feature | Milestone | Where | Action(s) | Remark |
|---|---|---|---|---|
| Open a terminal: login shell on a connected host (macOS, Linux, Windows) | core | D, M, W | terminal.open |
fresh step-up per opening, in the console passkey only (ADR 0070); screens D11, M8 |
Claude Code session in the terminal (profile claude) |
core | D, M, W | terminal.open |
interactive claude in a work folder from the allow list of the person's own session user (ruling T13), separate from the runner; only on hosts with a declared LLM login (I6) |
| Session list per host, detach and reattach, also from another device | core | D, M, W | terminal.read_own, terminal.attach |
the session keeps running for terminal.detach_grace; another device with a new step-up |
| End a session | core | D, M, W | terminal.close |
owners end any session |
Extra keys bar (Esc, Tab, Ctrl, Alt, arrows, \|, ~, /, -) and hardware keyboard |
core | M | build M5; screen M8 | |
| Host fingerprint and key pinning per device with a hard warning on a change | core | D, M, W | 24-terminal.md, section 5.5 | |
| Create a host, pair it, confirm the fingerprint, declare the LLM login, assign a session user per person, disable, retire | core | D, W | host.read, host.manage |
owner only, step-up, audit; without an own session user no terminal (SR12); screen A8 |
Grant terminal per host |
core | D, W | grant.create |
owner only; for non-owners it takes effect only on the host assigned to them (SR10); the preview says so |
| Take over a runner's thread in the terminal | later | D | only when runner and host service run as the same user in a dev environment (24-terminal.md, section 11.3) | |
| File transfer and clipboard through the terminal channel | later | D, M, W | blocked in this version (OSC 52, 24-terminal.md, section 11.2) | |
| Recording of terminal content | never | metadata only; whether evidence obligations require a recording is an owner question (default: no) | ||
| Terminal for agents or apps | never | an agent that prompt injection controls must not reach a host (T-TM-09) |
4. Information architecture¶
Instance (branding, status page)
+-- Spaces (sidebar, collapsible, category color, icon, default operator)
| +-- Text channel -> Main thread -> threads from messages
| +-- Forum -> Post list -> one thread per post (tags, Done section)
+-- Direct messages (later)
+-- Cross-cutting: Running now, Mentions, Search, Quick switcher, Settings
+-- Hosts (terminal): profiles and own sessions per host
+-- Live and statistics: live topology, executive page, timeline, TV mode
+-- Administration (desktop and web console; emergency actions on mobile)
Before login: server address, login, enrollment code, device waiting, pairing (5.6)
A thread is the same object with a fixed ID everywhere: in a forum a post, in a text channel a thread from a message. Its agent session, runs and costs are attached to it.
5. Screens¶
Symbols in the wireframes: v/> expanded/collapsed, # text channel, = forum, *
unread or run active, (3) counter, [ ] button or field, [A] agent (rounded square),
(AL) person (round), (o) running, [!] waiting for you, (@) mention, (z) queue,
(v) done, (x) failed, (-) cancelled. Trigger state on messages in
curly braces: {ok} done, {..} in progress, {z} queue, {x} failed,
{->} follow-up delivered. Rendered design: design system with the
images from docs/design/previews/.
5.1 Desktop (macOS, Windows)¶
D1 Main view, forum. Four columns: spaces and channels (brand surface), post list (forums
only), history with a pinned live box, right session column (collapsible, instead of a member
list). No server bar on the left (B13). Column borders can be dragged; widths are stored as the
setting layout.column_widths. Below ui.desktop_min_width_four_columns the session column
collapses, below ui.desktop_min_width_three_columns the post list does (navigation stack as on
the phone).
+----------------------------+--------------------------------+---------------------------------------+------------------------+
| [^] Bothy | = server [+ New post] | Gateway: resume after network change | Session [x] |
| [Jump to ... Cmd+K] | [Open][Waiting for me] | [Organization] 1,84 USD estimate | |
| (o) Running now (2) | [Tags v][Last activity v] | [Done] [Pin] [Column] | [A] dev-runner |
| | | +- (o) Running 4:12 62 % 0,62 USD -+ | online |
| v [H] Support | (o) Gateway: resume af.. 4min | | Checking if resume restores ... | | Backend [Organization] |
| # general | dev-runner [sync] | | [ok Read] internal/sync/gw.go | | Model model-large |
| | = requests * (3) | [!] Check migration 0012 12:41 | | [.. Bash] go test ./internal/... | | Session 0193f2a7-.. |
| # alerts (muted) | [Waiting for you] [db] | | > On resume, the focus is taken.. | | Project server, main |
| v [<>] Engineering | (@) Review: grant wizard 11:58 | | [Stop] Messages = follow-up | | |
| >= server * | Sam mentions you [access] | +-----------------------------------+ | Context [######----] |
| = apps | (z) Search: hits in tr.. 11:20 | [A] dev-runner AGENT 10:14 | Thread cost 1,84 USD |
| # releases | (v) Costs per space .. 2h | Cause: ... [code block] | (estimate) |
| > [M] Marketing * | (x) Upload limit ... yesterday | [v Ran 12 min, 3 tools >] | Runs 5 |
| > [R] Research | failed: project .. | [A] dev-runner AGENT 10:16 | |
| | (-) Old draft: export Mon | Approval needed: go test ... | Earlier sessions (2) |
| | | [Allow once][Session][Always] | Pinned (2) |
| | | |(SA) Sam: @Alex can you ... (!) | Files (3) |
| | | (AL) Alex 10:22 {..} @dev-runner ... | |
| | | ... Sam is typing | |
| (AL) Alex [Settings] | > Done (14) | [+] Follow-up to dev-runner [Mic][>] | |
+----------------------------+--------------------------------+---------------------------------------+------------------------+
D2 Text channel with an open thread. No post list. A thread opens to the right of the main thread; the session column is then collapsed. The header names the operator.
+--------------------------+------------------------------------------------+------------------------------------------+
| v [H] Support | # general Operator: support-agent [Topic] | #general > Request summary |
| ># general | | [Organization] [Done] [...] |
| = requests * (3) | (SA) Sam 09:12 | |
| # alerts | Customer asks about the export format. | [v] Ran 2 min, 1 tool, 0,04 USD > |
| | [Thread: Export format, 4 replies >] | [A] support-agent AGENT 09:31 |
| | (AL) Alex 09:30 {ok} | The request concerns ... (truncated) |
| | @support-agent summarize the request | [Show more] |
| | [Thread: Request summary 4711 >] | (AL) Alex 09:33 {->} |
| | (RO) Robin 09:41 | Please also name the deadline. |
| | Thanks, I'll take it from here. | |
| | | |
| | [+] Message to #general [Mic][>] | [+] Follow-up to support-agent [Mic][>] |
+--------------------------+------------------------------------------------+------------------------------------------+
D3 Thread view: live box in four states. Running (pinned), collapsed after the end, waiting for an answer, failed. Specification: components.md section 2. The expanded box has a button "Graph" that opens the run graph D14 (addendum of 2026-10-24).
+--------------------------------------------------------------------------------+
| (o) Running 4:12 Context 62 % 48,1k tokens 0,62 USD [Organization] [v] |
| Checking if resume restores the focus after the network change. |
| [ok Read ] internal/sync/gateway.go 0,4 s |
| [ok Grep ] resume_window 0,2 s |
| [.. Subagent] Write test cases for 4006 |
| [.. Bash] go test ./internal/sync/... running 38 s |
| 2 earlier steps [show] |
| > On resume, the focus is taken over from the gateway session; it is still |
| > open whether expired threads are dropped silently. |
| [Stop] New messages in this thread go to the run as a follow-up. |
+--------------------------------------------------------------------------------+
+--------------------------------------------------------------------------------+
| (v) Ran 28 min 3 tools 2 subagents 1,20 USD estimate [>] |
+--------------------------------------------------------------------------------+
+--------------------------------------------------------------------------------+
| [!] Waiting for you 2:03 0,18 USD [Personal] |
| Which database should the test use? |
| Database [Local container v] Port [55432 ] [Answer] |
+--------------------------------------------------------------------------------+
+--------------------------------------------------------------------------------+
| (x) Failed Backend mismatch: reported organization, configured personal |
| [Try again] [Details] |
+--------------------------------------------------------------------------------+
D4 Components on messages. Approval buttons (once, session, always, deny), selection, form; after use, a line with the person and the choice.
+--------------------------------------------------------------------------------+
| [A] dev-runner AGENT 10:16 |
| +- [Shield] Approval needed ------------------------------------------+ |
| | go test wants to use the network for the test database. | |
| | [Allow once] [For this session] [Always] [Deny] | |
| | [Lock] Only Alex or an owner can approve this. | |
| +---------------------------------------------------------------------+ |
| +- Choose model ------------------+ +- Question ---------------------+ |
| | [model-large v] | | Customer [Text ] | |
| | > model-large | | Priority [normal v] | |
| | model-fast | | [Submit] | |
| +---------------------------------+ +--------------------------------+ |
| After use: {ok} Alex chose 'Allow once', 10:24 |
+--------------------------------------------------------------------------------+
D5 Slash autocomplete. Opens on "/" at the start of a line. Commands of the operator first, commands of the same name from other agents with their handle. Options with suggestions from the agent.
+--------------------------------------------------------------------------------+
| +- Commands from dev-runner (operator of this channel) -------------------+ |
| | > /status State of the current run control command | |
| | /stop Cancel the run, never goes to the model control command | |
| | /model Choose a model for this session name | |
| | /stats Channel metrics research-bot | |
| +-------------------------------------------------------------------------+ |
| [+] /st| [Mic][>] |
| |
| After selection: /model [name: model-l|] Suggestions from the agent: |
| > model-large model-fast |
+--------------------------------------------------------------------------------+
D6 Quick switcher (Cmd+K or Ctrl+K). Jumps to a channel, thread, person, agent or command.
Results only from what is visible; recently visited targets first. At most
ui.quick_switch_max_results results.
+------------------------------------------------------------------------+
| [Lens] serv| [esc] |
+------------------------------------------------------------------------+
| > = server Engineering |
| [Thread] Gateway: resume after network change server |
| [A] dev-runner Agent |
| (SA) Sam Person |
+------------------------------------------------------------------------+
| Tab: Filter Channels | Threads | People | Agents | Commands |
+------------------------------------------------------------------------+
D7 Search. Full text across messages, thread titles, file names and transcripts; filters on the left; results with highlighting and path. The result count counts only what is visible.
+--------------------------+------------------------------------------------------------------------+
| Filter | [Lens] resume_window [Search] |
+--------------------------+------------------------------------------------------------------------+
| Space [all v] | 14 results, only from channels you may see |
| Channel [all v] | |
| From [all v] | = server > Gateway: resume after network change |
| Type [x] Messages | (A) dev-runner 10:14 ... window **resume_window** is measured |
| [x] Threads | from the last heartbeat ... |
| [x] Files | # releases > Version 0.4 |
| [ ] Transcripts | (RO) Robin yesterday ... new **resume_window** ... |
| Time [any v] | [File] notes-sync.md ... **resume_window** ... |
| Status [open+done] | [load more] |
+--------------------------+------------------------------------------------------------------------+
D8 Settings. Appearance, notifications, language, keyboard, devices and sessions, privacy, about (version, licenses). Under "Devices and sessions" the person confirms a waiting device with its code (E4) and adds a device with a pairing code (E5), both with step-up.
+--------------------------+------------------------------------------------------------------------+
| Settings | Appearance |
+--------------------------+------------------------------------------------------------------------+
| > Appearance | Theme ( ) System ( ) Light (x) Dark |
| Notifications | Density (x) Normal ( ) Compact |
| Language | Motion (x) System ( ) Full ( ) Reduced |
| Keyboard | Enter sends [x] (Shift+Enter: new line) |
| Devices and sessions | Column widths [Reset] |
| Privacy | |
| About | Language [German v] Time zone [Europe/Berlin v] |
| | Devices: iPhone (active), Laptop (this device), [Revoke device] |
| | Waiting: Tablet [Enter code] [Add device] |
| | Privacy: [x] Crash reports [x] Performance data [Export] |
+--------------------------+------------------------------------------------------------------------+
D9 Notification settings. Default, quiet hours, content in notifications, level per space, channel and thread with visible inheritance; time-limited muting. The row "Runs I triggered" is an explanation of 10.1, not a setting: a question of the person's own run always notifies, its end or failure follows the level; 13 3.3 has no key for it (docs/DECISIONS.md D-M4-33-4).
+------------------------------------------+--------------------------------------------------------+
| Notifications | |
+------------------------------------------+--------------------------------------------------------+
| Default for new channels | ( ) All (x) Mentions ( ) Mute |
| Runs I triggered | Questions always; done or failed by the level |
| Show content in notifications | [x] Load text (otherwise only 'New message') |
| Quiet hours | Mon-Fri 19:00-07:00, Sat-Sun all day [Edit] |
+------------------------------------------+--------------------------------------------------------+
| Per space, channel and thread | Level |
| v Support | [All v] |
| # general | [inherits: All] |
| = requests | [Mentions v] |
| v Engineering | [Mentions v] |
| = server > Gateway: resume ... | [All v] until [today 18:00 v] |
| > Marketing | [Mute v] |
+------------------------------------------+--------------------------------------------------------+
D10 Running now (control room). All active runs that the person may see; stop only where
run.cancel is allowed (triggering person, manage, owner). Addendum of 2026-10-24 (run
visualization, design note): the view has the switch "Cards" and
"List"; cards are the default. A card shows agent, path, state, duration, current tool, open
subagents, workflows and background jobs, the stall notice ("no movement since ..."), costs with
the suffix rules below, Stop where allowed, and opens the run graph D14 on click. Cards visible on
the screen are live; a card outside the live budget shows the summary with "live details paused"
(data: 09-agents.md, section 5.6). "List" shows the rows below and is also the form
for screen readers.
+----------------------------------------------------------------------------------------------------+
| Running now (3) [Cards | List] [Filter: Space v] [Agent v] [mine only] |
+----------------------------------------------------------------------------------------------------+
| +- dev-runner ---------------------------+ +- dev-runner ---------------------------+ |
| | (o) running 4:12 0,62 USD est. | | [!] waiting for you 2:03 | |
| | server > Gateway: resume after ... | | server > Check migration 0012 | |
| | [.. Bash] go test ./internal/sync/... | | Approval waiting | |
| | 2 subagents, 1 background job | | | |
| | [Graph] [Stop] | | [Graph] [Open] | |
| +----------------------------------------+ +----------------------------------------+ |
| +- research-bot -------------------------+ |
| | (~) running 31:40 | |
| | no movement since 12:41 | |
| | Research > Weekly report | |
| | live details paused | |
| | [Graph] [Stop] | |
| +----------------------------------------+ |
+----------------------------------------------------------------------------------------------------+
| Organization: sum of active runs 0,80 USD (estimate). Personal runs: information only. |
+----------------------------------------------------------------------------------------------------+
+----------------------------------------------------------------------------------------------------+
| Running now (3) [Cards | List] [Filter: Space v] [Agent v] [mine only] |
+----------------------------------------------------------------------------------------------------+
| (o) dev-runner server > Gateway: resume after network change 4:12 62 % 0,62 USD [Stop] |
| [!] dev-runner server > Check migration 0012 waiting for you 2:03 [Open] |
| (z) research-bot Research > Weekly report Queued [Open] |
+----------------------------------------------------------------------------------------------------+
| Organization: sum of active runs 0,80 USD (estimate). Personal runs: information only. |
+----------------------------------------------------------------------------------------------------+
D11 Terminal. Sidebar with the group "Hosts" below the spaces; on the right the terminal view
with one tab per own session on the host. The header shows the host, the connection, the badge of
the LLM login, the start of the fingerprint and the time left until
terminal.max_session_duration. "Detach" keeps the session running (it can be reattached), "End"
closes it. Opening requires confirmation with a passkey or a step-up device key; the dialog
names the host and the profile. All keys go to the shell, except the shortcuts from section 7.
+----------------------------+-------------------------------------------------------------------------------+
| [^] Bothy | Build host [online] [Organization] Fp 7KQ2 9XTA .. Left 11:42 [i] |
| [Jump to ... Cmd+K] | [shell 1 x] [claude: server x] [+ New session v] [Detach] [End] |
| (o) Running now (2) +-------------------------------------------------------------------------------+
| | ~/src/server $ go test ./internal/sync/... |
| > [H] Support | ok internal/sync 4.212s |
| v [<>] Engineering | ok internal/sync/gateway 1.874s |
| = server * | ~/src/server $ git status --short |
| # releases | M internal/sync/gateway.go |
| | ~/src/server $ _ |
| v Hosts | |
| (o) Build host (2) | |
| ( ) Linux VM | |
| (-) Test Windows | |
| disabled | |
| +-------------------------------------------------------------------------------+
| (AL) Alex [Settings] | End-to-end encrypted | Profile shell | Idle timeout active |
+----------------------------+-------------------------------------------------------------------------------+
Confirmation on opening and warning on a changed key (24, section 5.5):
+------------------------------------------------------------+ +------------------------------------------------------------+
| Open terminal | | [!] The host's key has changed |
+------------------------------------------------------------+ +------------------------------------------------------------+
| Host Build host | | Stored: 7KQ2 9XTA M4PB 1C8D ... |
| Profile (x) shell ( ) claude [Working folder: server v] | | Now: Q0ZJ 55RW 2HNE K7TS ... |
| Login [Organization] The organization bears the costs | | Without re-pairing by an owner, this is a sign of an |
| | | attack. Connect only after you have checked the new |
| Every opening is logged. | | fingerprint on the host. |
| [Cancel] [Confirm with passkey / device] | | [Do not connect] [Accept new key] |
+------------------------------------------------------------+ +------------------------------------------------------------+
D12 Live topology. Lanes per space, run cards with state, tool, badge and costs; a click opens the thread. The same data as a table via "Table". Normative: 25-visualization.md, section 6.1.
+----------------------------+-------------------------------------------------------------------------------+
| [^] Bothy | Live [Topology] [Backend] [Delivery] [Executive] [Timeline] |
| (o) Running now (3) | Space [all v] 12:04:31 live [Table] [TV mode] |
| v Live and statistics +-------------------------------------------------------------------------------+
| > Live | Engineering | = server +- dev-runner ------------------+ |
| Statistics | | | (o) running 4:12 | |
| | | | [.. Bash] go test | |
| > [H] Support | | | [Org.] 0,62 USD estimate | |
| v [<>] Engineering | | +-------------------------------+ |
| = server * | | # releases (no active runs) |
| v Hosts | Support | = requests +- support-agent ---------------+ |
| (o) Build host (2) | | | [!] waiting_input | |
| | | | Approval waiting [Personal] | |
| | | +-------------------------------+ |
| +-------------------------------------------------------------------------------+
| | Last minute: messages 14 | runs 3 | tool calls 41 | errors 0 |
+----------------------------+-------------------------------------------------------------------------------+
D13 TV mode. Full screen, dark theme, larger font, no controls; rotates through the selected
views every viz.tv_rotation_interval. Costs only with viz.tv_show_costs. A key press or a click
ends it. Desktop and web console, not mobile.
+--------------------------------------------------------------------------------------------------------+
| BOTHY LIVE Live topology (1 of 3) 12:04 [= = =] |
+--------------------------------------------------------------------------------------------------------+
| |
| ENGINEERING server [ (o) dev-runner running Bash Organization ] |
| releases [ (v) research-bot completed 2 min ] |
| |
| SUPPORT requests [ [!] support-agent waiting_input Approval waiting ] |
| |
| RESEARCH (no active runs) |
| |
+--------------------------------------------------------------------------------------------------------+
| Active runs 3 Tool calls/min 41 Delivery on target [ok] own measurement |
+--------------------------------------------------------------------------------------------------------+
D14 Run graph. Addendum of 2026-10-24 (run visualization,
design note). Opens from the button "Graph" of the live box
(D3) and from a card of D10. An indented trace view: the agent as the root row, subagents,
workflows and background jobs as child rows with their tools below them, each row with state
(color, icon and word), duration, current tool and cost where known (a child's cost only in
Organization mode, as "Estimate", 6.7); to the right a bar per row on
a shared time axis from the start of the run to now. The graph grows live while the run is
active; a finished run shows its final graph. A node with many finished children shows the newest
and "n earlier steps"; running nodes are never collapsed. Rows can be collapsed and expanded with
the mouse or the arrow keys. "As list" shows the same rows without bars as an outline for screen
readers. Data and derivation: 09-agents.md, section 5.6; permission run.read.
+----------------------------+-------------------------------------------------------------------------------+
| [^] Bothy | < Thread Run graph dev-runner (o) running 4:12 0,62 USD est. |
| (o) Running now (3) | server > Gateway: resume after network ... [As list] [Stop] |
| +-------------------------------------------------------------------------------+
| > [H] Support | 0:00 1:00 2:00 3:00 4:00 |
| v [<>] Engineering | (o) dev-runner [==========================================]|
| = server * | (v) Read internal/sync/... [=] |
| | (v) Grep resume_window [=] |
| | (o) Subagent Write test cases [==============================]> |
| | (v) Read gateway_test.go [=] |
| | (o) Bash go test ./... [===================]> |
| | (o) Background job npm test [============================]> |
| | (x) Subagent Check migration [=======] failed |
| | 3 earlier steps [show] |
+----------------------------+-------------------------------------------------------------------------------+
5.2 Administration (desktop and web console)¶
Before it is submitted, every changing administration action with step-up shows the confirmation with passkey or device key (08-identity.md).
A1 People. List, create (no self-registration, no invitation links), queue of new devices with the origin of the login.
+------------------------+----------------------------------------------------------------------------+
| Administration | People [+ Add person] |
+------------------------+----------------------------------------------------------------------------+
| > People | [Lens] Search Filter: [active v] [Group v] |
| Groups | (AL) Alex Owner 2 devices last seen today |
| Grants | (SA) Sam Support (trigger) 1 device last seen today |
| Devices (1 waiting) | (RO) Robin Engineering (trigger) 3 devices yesterday |
| Agents | (NE) New waiting for login |
| Apps | --- |
| Audit | Waiting devices: Sam, 'Pixel', logged in 08:12 via OIDC |
| Statistics | [Approve] [Reject] Key: hardware, attested |
| Instance | |
+------------------------+----------------------------------------------------------------------------+
A2 Create grant with plain-language preview. Three steps (who, where, level and capabilities). The preview states the effect in sentences, names newly visible channels and checks I1 before submitting; a violation is explained, not just rejected ("switch to organization first").
+----------------------------------------------------------------------------------------------+
| Create grant Step 3 of 3 |
+----------------------------------------------------------------------------------------------+
| Who (SA) Sam [Person v] |
| Where Support space (applies to all channels in it) |
| Level ( ) read ( ) write (x) Trigger agents |
| Capabilities [ ] Approve actions [x] Upload files [ ] Export [ ] Manage |
| Until [x] 31.12.2026 Reason [Support cover Q4 ] |
+----------------------------------------------------------------------------------------------+
| Plain-language preview: |
| From now on Sam may read all channels in the Support space, write there and trigger |
| the agent support-agent. Sam may upload files. Sam may not approve |
| actions (approval buttons stay disabled). Valid until 31.12.2026. |
| Newly visible for Sam: 3 channels, 214 threads. |
| [!] Check: support-agent runs in Organization mode. The organization bears the costs. |
| [x] Would be rejected: dev-runner (Personal, only Alex may trigger). Switch first. |
+----------------------------------------------------------------------------------------------+
| [Back] [Confirm with passkey / device] |
+----------------------------------------------------------------------------------------------+
A3 Who has access? Per space or channel: people, groups, agents with effective level and origin (direct, group, inherited, owner).
+--------------------------------+----------------------------------------------------------------+
| Who has access? | Space Support > Channel requests |
+--------------------------------+----------------------------------------------------------------+
| Person or group | Level, capabilities and origin |
+--------------------------------+----------------------------------------------------------------+
| (AL) Alex | trigger, all capabilities Owner |
| (SA) Sam | trigger, files direct on space Support, until 31.12. |
| [G] Support team (4) | write group, inherited from space Support |
| (RO) Robin | read via group Support team and direct |
| [A] support-agent | write (operator) direct on space Support |
+--------------------------------+----------------------------------------------------------------+
| [View as person v] | [Create grant] [Revoke] [History] |
+--------------------------------+----------------------------------------------------------------+
A4 View as person. Read-only; clear frame; every use in the audit log.
Console (M6-04, docs/decisions.d/M6-04.md D-M6-04-3): the console shows structure and access only.
Starting the view from A3 or A1 calls viewAsUser; the console shows the spaces and channels of
the answer as a structure list and the "Not visible" list (the spaces the owner sees and the
person does not), and keeps the banner with name and remaining time on every page until
endViewAs or the end time of getConsoleSession. A click on a channel opens nothing, because
the console has no content routes (ADR 0028); the desktop app keeps showing content read-only.
+----------------------------------------------------------------------------------------------+
| [Eye] Viewing as Sam (read-only). Nothing is sent. Logged. [Exit] |
+----------------------------------------------------------------------------------------------+
| Sidebar as Sam sees it: v Support (# general, = requests, # alerts) |
| > Research (# reading-club) |
| Not visible for Sam: Engineering, Marketing |
| Clicking a channel shows content as for Sam; input, buttons and reactions are off. |
+----------------------------------------------------------------------------------------------+
A5 Agents with backend switch and costs. Reported mode from the heartbeat next to the configured mode; switching with reason and step-up; explanation of why Personal is not possible right now (I1).
+--------------------------------+----------------------------------------------------------------+
| Agents | support-agent [online] |
+--------------------------------+----------------------------------------------------------------+
| > support-agent [Org.] | Adapter hermes Reported mode: Organization |
| dev-runner [Pers.] | Operates space Support (default), # alerts |
| research-bot [Org.] | Backend (x) Organization ( ) Personal |
| | Switching needs reason and confirmation. |
| [Switch all ...] | Personal only works if exactly one person |
| | may trigger (I1). Today: 5 people. |
| | Costs 30 days 41,20 USD (estimate) [by space v] |
| | Support 38,10 Marketing 3,10 [Reconcile] |
| | Tokens [Create token] Commands (6) Presence history |
+--------------------------------+----------------------------------------------------------------+
A6 Audit. Filterable by action, person, result, resource, time range; check of the hash chain. Export of a time range as the server's NDJSON with hashes (verifiable offline) and as CSV, which the device converts from the same stream.
+----------------------------------------------------------------------------------------------------+
| Audit Filter: [Action v] [Person v] [Result: all v] [Time range v] [Check chain] |
+----------------------------------------------------------------------------------------------------+
| Time Who Action Result Resource Reason |
| 10:24 Alex interaction.create allowed Card in server approve_actions |
| 10:20 Sam interaction.create denied Card in server missing capability |
| 09:58 Alex grant.create allowed Space Support Cover Q4 |
| 09:57 Alex auth.step_up allowed Session laptop |
| 08:12 Sam agent.invoke denied Run 0193.. Personal: not holder |
+----------------------------------------------------------------------------------------------------+
| Chain checked up to no. 18 402: unchanged. [Export] [Export as CSV] (owner, step-up) |
+----------------------------------------------------------------------------------------------------+
A7 Statistics. Metric tiles, runs per day, costs per agent and space, failure reasons. Values from the server; the console shows the same view at full width.
+----------------------------------------------------------------------------------------------------+
| Statistics Time range [30 days v] Space [all v] [Export] |
+----------------------------------------------------------------------------------------------------+
| + Runs -----------+ + Costs (Org.) ----+ + Mean duration --+ + Waiting for people --+ |
| | 1 284 | | 41,20 USD | | 3 min 10 s | | 12 open | |
| | +8 % vs prev. | | Estimate | | p95 18 min | | oldest 2 days | |
| +-----------------+ +------------------+ +------------------+ +----------------------+ |
| Runs per day (stacked by result) Costs per agent |
| :::::::::::::::::::::::::::::::::::: support-agent ########## 38,10 |
| done / failed / canceled research-bot # 3,10 |
| Failure reasons: project not ready 9, backend mismatch 2, time limit 1 |
+----------------------------------------------------------------------------------------------------+
A8 Hosts. Owner only. Create a host with name, optional assignee and reason; one-time
pairing code with a command for the host; confirmation by typing the first
terminal.fingerprint_confirm_chars characters of the fingerprint that bothy-host pair shows there;
mandatory questions about the LLM login (I6) and the server host; mapping of each person to their own
session user on the host, as a choice from the names that the host reports
(hosts.reported_session_users; without a mapping no terminal, SR12); per session user its
work folders of the profile claude (ruling T13); check results of bothy-host doctor
with each session user or former session user that the message names (rule for names: HD6, HD10,
HD11 and HD9) and the person mapped to it, even when the
host is disconnected after a refused start (24, section 2.2); disable,
re-pair, retire. Every change with step-up and reason.
+------------------------+----------------------------------------------------------------------------+
| Administration | Hosts > Build host [active] [Disable v] |
+------------------------+----------------------------------------------------------------------------+
| People | Assignee (RO) Robin [Change] |
| Groups | Platform macOS, host service 1.2.0 connected since 07:58 |
| Grants | Fingerprint 7KQ2 9XTA M4PB 1C8D ... Key generation 2 |
| Devices | LLM login (x) Organization ( ) Personal of [Person v] ( ) None |
| Agents | Personal: only this person may open a terminal here |
| > Hosts (3) | (I6), not even other owners. |
| Apps | Server host ( ) yes (x) no Report of the host service: no |
| Audit | Checks HD1 ok HD2 ok HD3 ok HD4 ok HD5 ok HD6 ok HD7 warning |
| Statistics | HD8 ok HD9 ok HD10 ok HD11 failed: bothy-s-alex |
| Instance | Profiles shell, claude |
| | Grants (RO) Robin terminal effective (assignee) |
| | (SA) Sam terminal not effective: not assignee (SR10) |
| | Session users (RO) Robin: bothy-s-robin Work folders: server, apps |
| | (AX) Alex (Owner): bothy-s-alex Work folders: none |
| | reported, not mapped: bothy-s-sam [Map] |
| | without a session user no terminal (SR12) |
| | [Re-pair] [Sessions (2)] [Retire] |
+------------------------+----------------------------------------------------------------------------+
Pairing a new host:
+----------------------------------------------------------------------------------------------+
| Pair host Step 2 of 3 |
+----------------------------------------------------------------------------------------------+
| Run on the host as the user of the host service (one-time code, expires soon): |
| bothy-host pair --server https://chat.example.com --code bothy_hpc_EXAMPLE... |
| [Copy] Expires in 14:12 |
+----------------------------------------------------------------------------------------------+
| Step 3: Type the fingerprint from the host (first characters) [7KQ2 9XTA] |
| LLM login on this host ( ) None ( ) Personal ( ) Organization |
| Does the server run on this host? ( ) yes ( ) no |
| Session user per person: [Person v] -> [reported name v] [+] |
| (only names that the host reported during pairing) |
+----------------------------------------------------------------------------------------------+
| [Back] [Confirm with passkey / device] |
+----------------------------------------------------------------------------------------------+
5.3 iPhone¶
Navigation stack: spaces -> channel or post list -> history. Back by swiping from the edge.
Input at the bottom with spacing to the safe areas. Touch targets density.target-min (context
touch). A push opens the thread directly at the message.
M1 Spaces.
+--------------------------------------+
| [^] Bothy [Lens] |
| (o) Running now (2) |
| v [H] Support |
| # general |
| | = requests * (3) |
| # alerts |
| v [<>] Engineering |
| = server * |
| > [M] Marketing * |
| |
+--------------------------------------+
| [Spaces] [Mentions] [Running] [Me] |
+--------------------------------------+
M2 Post list.
+--------------------------------------+
| < Support = requests [+] |
| [Open][Waiting for me][Tags] |
+--------------------------------------+
| (o) Gateway: resume after netw.. |
| dev-runner [sync] 4 min |
| [!] Check migration 0012 |
| [Waiting for you] 12:41 |
| (@) Review: grant wizard |
| (v) Costs per space 2 h |
| |
| > Done (14) |
+--------------------------------------+
M3 History with compact live box. Stop is always reachable at the top right of the live box row; tapping opens the full live box as a sheet. Approval buttons stacked at full width. The sheet has a button "Graph" that opens M12 (addendum of 2026-10-24).
+--------------------------------------+
| < server Gateway: resume ... ... |
+--------------------------------------+
| (o) Running 4:12 62 % [STOP] |
| go test ./internal/sync/... |
+--------------------------------------+
| [A] dev-runner 10:16 |
| Approval needed: go test ... |
| [ Allow once ] |
| [ For this session ] |
| [ Deny ] |
| (AL) Alex 10:22 {..} |
| Please include expired threads. |
+--------------------------------------+
| [+] Follow-up to dev-runner [Mic] |
+--------------------------------------+
M4 Large components. Like M3: buttons at full width, forms as a sheet with keyboard; selection as the system picker.
M5 Record voice message. Press and hold the microphone; swiping left discards, swiping up
locks the recording; releasing sends. Maximum duration voice.max_duration (12-files.md, delivered by instance.read); a
notice before it runs out.
+--------------------------------------+
| < server Gateway: resume ... |
| |
| |
+--------------------------------------+
| ( * ) 0:17 Recording |
| ||||||||||| ||||| |||||| |
| |
| <- swipe to discard |
| ^ swipe up to lock |
| [Release = send] |
+--------------------------------------+
| [Press and hold Mic] |
+--------------------------------------+
M6 Share from other apps (choose target). Separate sheet of the Share Extension: preview, comment, target from recently used threads and channels with write permission, search for more. Sending goes directly; without network the entry lands in the app's queue.
+--------------------------------------+
| Cancel Share to [Send] |
+--------------------------------------+
| [Image] screenshot.png 1,2 MB |
| Comment [See error above ] |
+--------------------------------------+
| Target |
| > = server > Gateway: resume .. |
| = requests (new post) |
| # general |
| [Lens] Search others ... |
+--------------------------------------+
| Only targets with write permission. |
+--------------------------------------+
M7 Offline. Banner at the top; waiting messages with "sending"; permanent errors with reason and buttons; nothing is discarded silently.
+--------------------------------------+
| < server Gateway: resume ... |
| [Cloud] Offline. 1 message waiting |
+--------------------------------------+
| (AL) Alex 10:22 {..} |
| Please include expired threads. |
| (AL) Alex |
| And summarize afterwards. |
| {z} sending |
| (AL) Alex |
| Attachment too large. {x} failed |
| [Retry] [Edit] [Discard] |
+--------------------------------------+
| [+] Message (will be sent later) |
+--------------------------------------+
M8 Terminal with extra keys bar. Full-screen view of a session. Above the system keyboard
sits the extra keys bar: Esc, Tab, Ctrl, Alt, arrows, |, ~, /, -. Ctrl and Alt
act once for the next key; tapping twice holds them until the next tap (indicator
filled). With a hardware keyboard the app hides the bar. Swiping with two fingers scrolls
the scrollback; a long press selects text for copying. When the app goes to the background, it
detaches the session (it keeps running on the host) and hides the view in the app switcher; back
in the app it reattaches within terminal.quick_reattach_window without a new confirmation,
after that with Face ID or fingerprint.
+--------------------------------------+
| < Hosts Build host [Org.] |
| shell 1 v Left 11:42 [Detach] |
+--------------------------------------+
| ~/src/server $ git status |
| On branch main |
| nothing to commit, working tree clean|
| ~/src/server $ tail -f run.log |
| 12:04:31 sync: resume ok |
| 12:04:32 sync: catch-up 14 events |
| _ |
+--------------------------------------+
| [Esc][Tab][Ctrl][Alt] [<][^][v][>] |
| [ | ] [ ~ ] [ / ] [ - ] [Keybd.] |
+--------------------------------------+
| q w e r t z u i o p |
| a s d f g h j k l |
| [^] y x c v b n m [<-] |
| [123] [ Space ] [Enter] |
+--------------------------------------+
M9 Hosts and sessions. List of the hosts that the person may see, with connection, badge of the LLM login and own sessions; tapping a session attaches.
+--------------------------------------+
| < Me Hosts |
+--------------------------------------+
| (o) Build host [Org.] |
| shell 1 detached 3 min ago |
| claude: server active |
| [+ New session] |
| ( ) Linux VM [None] |
| offline since 08:12 |
+--------------------------------------+
| Fingerprint and login: [i] |
+--------------------------------------+
M10 Live. The same views as D12 from bothy_viz in density touch, one tab per view:
topology, backend, delivery, executive, timeline. The topology stacks the lanes vertically;
tapping a run card opens the thread. Every view has the table view. The live stream
runs only in the foreground. No TV mode. Normative: 25-visualization.md,
section 6.
+--------------------------------------+
| < Me Live 12:04:31 live |
| [Topo][Backend][Deliv.][Exec][Time] |
+--------------------------------------+
| Engineering |
| = server |
| +- dev-runner -------------------+ |
| | (o) running 4:12 [.. Bash] | |
| | [Org.] 0,62 USD estimate | |
| +--------------------------------+ |
| Support |
| = requests |
| +- support-agent ----------------+ |
| | [!] waiting_input | |
| | Approval waiting [Personal] | |
| +--------------------------------+ |
+--------------------------------------+
| Last minute: runs 3 | errors 0 |
| [Table] |
+--------------------------------------+
M11 Running now (control room). Addendum of 2026-10-24 (run visualization). D10 in density
touch from the tab "Running": cards in one column, the switch "Cards" and "List", filters as a
sheet. A tap on a card opens M12; Stop where allowed. Visible cards are live only while the app is
in the foreground. Data: 09-agents.md, section 5.6.
+--------------------------------------+
| Running now (3) [Cards | List] |
| [Space v] [Agent v] [mine only] |
+--------------------------------------+
| +- dev-runner ---------------------+ |
| | (o) running 4:12 0,62 USD est. | |
| | server > Gateway: resume ... | |
| | [.. Bash] go test ./... | |
| | 2 subagents, 1 background job | |
| | [STOP] | |
| +----------------------------------+ |
| +- research-bot -------------------+ |
| | (~) running 31:40 | |
| | no movement since 12:41 | |
| +----------------------------------+ |
+--------------------------------------+
| [Spaces] [Mentions] [Running] [Me] |
+--------------------------------------+
M12 Run graph. Addendum of 2026-10-24 (run visualization). D14 in density touch: the same
rows, indented, with a narrow time bar below each label; in landscape the bars stand beside the
labels on the full time axis. A tap on a row collapses or expands it; "As list" as in D14.
+--------------------------------------+
| < Running Run graph [As list] |
| (o) dev-runner 4:12 0,62 USD est. |
+--------------------------------------+
| (o) dev-runner |
| [==============================] |
| (o) Subagent Write test cases |
| [ ===================> ] |
| (o) Bash go test ./... |
| [ ==========> ] |
| (o) Background job npm test |
| [ ==================> ] |
| (x) Subagent Check migration |
| [ ===== ] |
| 3 earlier steps [show] |
+--------------------------------------+
| [STOP] |
+--------------------------------------+
M13 Emergency. Addendum of 2026-10-25 (M5-09; R-PR-07). The entry "Emergency" under Me
shows only for an owner or for a person who manages at least one space (the owner flag of
getMe and the capability manage the server reported for a space). It lists people with a
search; a person shows their devices with "Revoke" and "Disable person" (owners only) and their
access grants with "Revoke" (the grants the server lists for the caller). Each action opens a
sheet that says what happens and that it takes effect at once; the button names the step-up
("Confirm with Face ID", on Android the fingerprint or screen lock), and a cancelled step-up
sends nothing. Stopping a run stays in the live box (M3) and in Running now (M11). Nothing else
of the administration is on the phone.
+--------------------------------------+
| < Emergency |
| (SA) Sam @sam [Active] |
| [ Disable person ] |
| Devices |
| Pixel Android today 08:12 [Revoke] |
| Access grants |
| Space Support |
| Write, until Dec 31, 2026 |
| [Revoke] |
+--------------------------------------+
| Revoke the access grant for Sam? |
| [!] The access grant of Sam on Space |
| Support is revoked at once. |
| [Reason ] |
| [ Confirm with Face ID ] |
| [ Cancel ] |
+--------------------------------------+
5.4 Android¶
Same screens as iPhone, with Android controls: system back, top app bar, notification channels of the system, sharing via the system share sheet into the same target selection. In the terminal (M8), system back detaches the session instead of ending it; the extra keys bar is the same.
+--------------------------------------+
| [<-] Gateway: resume ... [:] |
+--------------------------------------+
| (o) Running 4:12 62 % [STOP] |
| ... |
+--------------------------------------+
| System back: to the post list |
| Notification channels in the |
| system settings: Mentions, |
| Questions, All messages, Runs |
| Share: system sheet -> app -> |
| same target sheet as iOS |
+--------------------------------------+
5.5 Web console (administration, statistics and terminal)¶
Same administration screens as A1 to A8, the views from D12 and D13 and the terminal from D11, navigation on the left. No chat (ADR 0028); links to threads open the app via deep link. The run graph D14 and the control room D10 are not part of the console (addendum of 2026-10-24): both show run content that the console, without chat, has no place for; D12 stays its live view. The terminal opens only after confirmation with a passkey with user verification; other step-up methods of the console do not count for it (ADR 0070).
+--------------------------+------------------------------------------------------------------------+
| [^] Bothy console | Statistics Logged in: Alex (passkey) |
+--------------------------+------------------------------------------------------------------------+
| Live | (like desktop statistics, full width) |
| > Statistics | |
| Hosts and terminal | No chat in the browser. Links in threads open the app: |
| People | [Open in the app] (deep link) |
| Groups, grants | |
| Devices | Terminal: opens only with passkey; pinned host keys are kept in |
| Agents, costs | the storage of this browser and are deleted at logout. |
| Apps, webhooks | |
| Audit | |
| Import | |
| Instance, branding | |
| Status | |
+--------------------------+------------------------------------------------------------------------+
5.6 Onboarding and sign-in (all apps)¶
Screens E1 to E7 apply equally to desktop, iPhone and Android; the flows behind them are in 08-identity.md. On the phone they fill the screen; on the desktop they appear as a card in the center of an empty window with the branding of the instance. The wireframes show the phone form, E2 also the desktop form. The web console uses only E2 and E7: it has no device confirmation, but requires a step-up after the login (08, section 7.5).
Rules for all onboarding screens:
- No content of the instance before the login, only name, logo and accent from
getDiscovery(branding). - Every code is set in groups, in a mono font (
font.family.mono), can be copied and is read character by character by the screen reader. Input fields for codes accept pasting and ignore case, spaces and hyphens (08, section 3.2). - Remaining times appear as text, not only as bars; the screen reader announces them at most once
per
a11y.live_announce_min_interval. - Error texts name the cause and the next step; the response to a wrong code is always the same (08, section 3.2).
- Keyboard: Enter triggers the main action, Esc goes back one step; the focus order follows the reading direction.
E1 Server address (first start). One field for the address of the instance. "Connect" calls
getDiscovery. Results: on to E2; "No instance at this address" (no
valid response); "Certificate invalid" (no continue, no exception button); "Instance not set up
yet" on setup_required with a pointer to the setup wizard on the host
(16-operations.md, section 3.1); "App too old" below min_client_versions with the
update path (18-release.md). The app remembers the address; a second server is
not planned (B13).
+--------------------------------------+
| |
| [Logo] |
| Connect to your instance |
| |
| Server address |
| [https://chat.example.com ] |
| |
| [ Connect ] |
| |
| Instance not set up yet: |
| The owner sets it up on the |
| host (install.sh). [More] |
+--------------------------------------+
E2 Login. Name and logo of the instance at the top. Below them, one button per provider from
auth_providers with its name: OIDC opens the system browser (08, section 14.1); a proxy provider
(trusted_header) logs in without input (08, section 2.4). If a local driver is active: a field
for the login name, "Log in with passkey" (native apps only with a public domain, 08,
section 2.5) and, if local_password_enabled, "Password and one-time code" with a second step for
the TOTP code (autofill for the system's one-time codes on). At the bottom always "I have an
enrollment code" (E3) and "Pair with another device" (E5). If no method exists, it says
"No login is set up for this instance" with a pointer to the owner.
+--------------------------------------+
| < Server chat.example.com |
+--------------------------------------+
| [Logo] |
| Log in to Team Chat |
| |
| [ Log in with Company SSO ] |
| -------------- or -------------- |
| Login name [alex ] |
| [ Log in with passkey ] |
| [ Password and one-time code ] |
| |
| I have an enrollment code |
| Pair with another device |
+--------------------------------------+
Desktop: the same card in the center; the sidebar stays empty until the login succeeds.
+------------------------------------------------------------------------------------+
| |
| +----------------------------------------+ |
| | [Logo] | |
| | Log in to Team Chat | |
| | [ Log in with Company SSO ] | |
| | ---------------- or ---------------- | |
| | Login name [alex ] | |
| | [ Log in with passkey ] | |
| | [ Password and one-time code ] | |
| | Enrollment code Pair device | |
| | Server: chat.example.com [Change] | |
| +----------------------------------------+ |
| |
+------------------------------------------------------------------------------------+
E3 Redeem enrollment code. For the first device and for recovery (08, section 3.2).
First the code, then the method that the instance offers: "Create passkey", "Set up password and
one-time code" (two steps with a QR code of the one-time code and confirmation, 08, section 2.5) or
"Link with login service" (OIDC or proxy). A redeemed code makes this device
active immediately; the app goes straight to the main view.
+--------------------------------------+
| < Login Enrollment code |
+--------------------------------------+
| Code from the owner |
| [en_ 7K2M-9QXA-... ] |
| |
| How do you want to log in? |
| (x) Create passkey |
| ( ) Password and one-time code |
| ( ) Link with Company SSO |
| |
| [ Continue ] |
| The code is valid once. |
+--------------------------------------+
E4 Device waiting for confirmation. After a login on a new device (08, section
5.2). The confirmation code appears large in the center (auth.device_verification_code_digits
digits), below it the instructions: type in the code on an active device under Settings, Devices,
or ask an owner. The remaining time until auth.device_pending_ttl appears as text.
"Cancel" logs out and deletes the keys of the device. The app polls the state; after the
confirmation it goes to the main view, after rejection or expiry to E7.
+--------------------------------------+
| Device waiting for confirmation |
+--------------------------------------+
| |
| 4 8 1 2 0 7 |
| |
| Type this code on one of your |
| active devices: Settings, |
| Devices and sessions, Confirm. |
| No active device: ask the owner. |
| |
| Valid for 23 more minutes |
| [ Cancel ] |
+--------------------------------------+
E5 Pair with another device. The new device shows a pairing code with
auth.pairing_code_chars characters and the remaining time until auth.pairing_code_ttl (08, section
5.3). On the active device, "Add device" (D8, Devices and sessions) opens a field for the
code and the step-up. After that the new device is active.
+--------------------------------------+
| < Login Pair device |
+--------------------------------------+
| On an active device: |
| Settings > Devices > |
| Add device, then enter: |
| |
| HQ7P - 3MXR |
| |
| Valid for 4 more minutes |
| [ New code ] |
+--------------------------------------+
E6 App lock. After client.app_lock_after without use and at start, if the person has turned
it on or security.app_lock_required applies (08, section 9). The content is
hidden, also in the app switcher. A button calls the system's biometrics or device PIN; after
a failure the lock stays with "Try again". "Log out" leads to E7 and deletes the
local data. The lock detaches terminal sessions (they keep running on the host, 5.3, M8).
+--------------------------------------+
| |
| [Logo] |
| Team Chat is locked |
| |
| [ Unlock with Face ID ] |
| |
| Log out |
+--------------------------------------+
E7 Logged out. After logout, revocation of the device, expiry of the session
(auth.session_max_age), disabling of the person or rejection in E4. The reason appears as text
(devices.revoke_reason or the code of the session, without internal names), together with the
sentence "The data of this device has been deleted" (04, section 8.5, R-SY-14) and "Log in again"
(E2). For a disabled person there is no login button, only "Contact the owner".
+--------------------------------------+
| |
| You are logged out. |
| Reason: This device was revoked |
| by another device. |
| |
| The data of this device has |
| been deleted. |
| |
| [ Log in again ] |
+--------------------------------------+
6. Interaction rules¶
6.1 Done and reopening¶
- "Done" (
thread.close) in the thread header, in the context menu of the post list and via shortcut. - Done posts are at the bottom in the section "Done (n)", collapsed by default; the collapse state is personal per forum. The collapse state is kept per forum on each device in the local database and is not synchronized, because 11 has no setting key for it (docs/DECISIONS.md D-M4-19-4).
- A new message in a done thread reopens it (
thread.reopenimplicitly). The history shows a system line "Reopened by message from Sam". A system line itself does not reopen a done thread (03-data-model.md, R-DM-42). - The word "done" as a message is not a command; the way is the button or a command that an agent registers.
6.2 Live box¶
- While a run is active, the live box is pinned at the top of the thread; at the end it collapses into one line at its place in the history ("Ran 28 min · 3 agents · USD 1.20 estimate").
- Expanding loads the run document; during the run, changes arrive only while the thread is visible (focus, 04 section 11).
- Stop asks for no confirmation; it is harmless and must be fast.
- The button "Graph" opens the run graph (D14, M12) with the same document; it follows the same focus rule (addendum of 2026-10-24).
- A stall after
run.stall_aftershows a notice in the live box, no push. - Follow-ups: during an active run, the input is labeled "Follow-up to
". The trigger state of the message changes to "Follow-up delivered" as soon as the adapter has handed it over.
6.3 Trigger state as icons¶
Instead of status emoji, the triggering message shows an icon with a label in the tooltip and in the screen reader label. Icons and colors: components.md section 5.
trigger_state |
Meaning for the person |
|---|---|
received |
The server has accepted the message. |
queued |
A run has been created and is waiting. |
working |
The agent is working. |
done |
The run is finished. |
failed |
Triggering or the run has failed; the reason is shown with it. |
followup_delivered |
The follow-up has reached the running agent. |
6.4 Long replies¶
Messages over ui.message_collapse_lines lines are collapsed with "Show more";
code blocks scroll horizontally instead of wrapping. Long replies are never split across several
messages.
6.5 Components¶
Buttons apply once and only for those authorized. Whoever is not authorized sees them disabled
with a reason ("Only the triggering person or an owner"). After use, the card shows person, choice
and time. Expired components (component.default_ttl) show "Expired". Double clicks do not create
a second interaction.
6.6 Offline and queue¶
- Banner "Offline" at the top of the content; connecting runs in the background with backoff.
- Sent messages appear immediately with "sending" at the end of the thread.
- Permanent errors show the reason with "Send again" (new ID), "Edit", "Discard".
- If the person loses access, open views close with "No access anymore"; waiting messages remain as text for copying.
- After reconnecting, the app first catches up and then sends (04 section 13.4).
6.7 Other rules¶
- Not found instead of forbidden. A link to something invisible shows "Not found or no access", regardless of whether it exists (B7).
- Mention suggestions show only people and agents that the person may see.
- Titles: automatically set titles carry a small "automatic" mark; editing makes the title manual.
- Operator: The channel header names the operator. Without an operator it says "No agent answers here"; so an agent never answers in the wrong channel unnoticed.
- Costs: in Organization mode with "Estimate" until reconciled; in Personal mode with "Information only".
- Destructive actions (delete a message, revoke a grant, revoke a device) ask for confirmation once; administration actions with step-up ask for the confirmation of the device.
- Move: The dialog shows only channels with the same operator; the thread ID stays.
7. Keyboard shortcuts¶
Shortcuts apply on desktop. They avoid system assignments (Cmd+H, Cmd+M, Cmd+Q, Alt+F4, Windows key). There is no shortcut that triggers an approval.
| Action | macOS | Windows |
|---|---|---|
| Quick switcher | Cmd+K | Ctrl+K |
| Search | Cmd+Shift+F | Ctrl+Shift+F |
| Search in thread | Cmd+F | Ctrl+F |
| New post or new chat in the current forum | Cmd+N | Ctrl+N |
| Focus the input | Esc then Tab, or Cmd+L | Esc then Tab, or Ctrl+L |
| Next or previous channel | Option+Arrow down / up | Alt+Arrow down / up |
| Next or previous unread channel | Option+Shift+Arrow down / up | Alt+Shift+Arrow down / up |
| Switch column (sidebar, list, history, session) | F6 / Shift+F6 | F6 / Shift+F6 |
| Mark thread as read | Esc | Esc |
| Mark as unread (from a message) | Option+Click | Alt+Click |
| Mark thread as done or reopen it | Cmd+Shift+E | Ctrl+Shift+E |
| Stop the run in the current thread | Cmd+. | Ctrl+. |
| Expand and collapse the live box | Cmd+Shift+L | Ctrl+Shift+L |
| Show and hide the session column | Cmd+Shift+I | Ctrl+Shift+I |
| Edit the last own message | Arrow up in the empty field | Arrow up in the empty field |
| Send / new line | Enter / Shift+Enter (reversible) | Enter / Shift+Enter (reversible) |
| Running now | Cmd+Shift+R | Ctrl+Shift+R |
| Mentions | Cmd+Shift+M | Ctrl+Shift+M |
| Settings | Cmd+, | Ctrl+, |
| List of shortcuts | Cmd+/ | Ctrl+/ |
| Open hosts and terminal | Cmd+Shift+T | Ctrl+Shift+T |
In the terminal all keys go to the shell, including Ctrl combinations such as Ctrl+C, Ctrl+D and Ctrl+K. App shortcuts work there only with the platform modifier: on macOS with Cmd, on Windows with Ctrl+Shift. Reason: shells and coding agents use Ctrl and Alt themselves; an app shortcut must not swallow any input (R-PR-10).
| Action in the terminal | macOS | Windows |
|---|---|---|
| Copy / paste | Cmd+C / Cmd+V | Ctrl+Shift+C / Ctrl+Shift+V |
| Quick switcher | Cmd+K | Ctrl+Shift+K |
| New session on this host | Cmd+T | Ctrl+Shift+N |
| Next or previous session | Cmd+Shift+] / [ | Ctrl+Shift+Arrow right / left |
| Detach session (keeps running) | Cmd+Shift+D | Ctrl+Shift+D |
| Search in the scrollback | Cmd+F | Ctrl+Shift+F |
| Font larger / smaller | Cmd+Plus / Cmd+Minus | Ctrl+Shift+Plus / Ctrl+Shift+Minus |
8. Accessibility¶
Goal: WCAG 2.2 level AA (https://www.w3.org/TR/WCAG22/, retrieved 2026-10-10 [verified]) in apps and console, checked by tests, not by intention.
| Topic | Rule | Check |
|---|---|---|
| Contrast | Every text and icon pairing reaches AA (text 4.5:1, UI 3:1) in light and dark | Gate tokens.py check (contrast.md); widget tests with textContrastGuideline |
| Screen reader | VoiceOver, TalkBack, Narrator; in the console NVDA and VoiceOver. Every component has a role and a label; live box as a container with a summary; trigger state as its own label | Widget tests with labeledTapTargetGuideline; semantics snapshots per component |
| Live content | Only state changes and questions are announced, at most once per a11y.live_announce_min_interval; patches never |
Test with a simulated patch stream |
| Font size | System scaling up to 200 percent without loss (SC 1.4.4); the layout wraps into the stack | Golden tests with text scaling 1 and 2 |
| Focus | Order per column (sidebar, list, history, input, session); F6 switches columns; focus ring always visible | Integration test of a keyboard pass |
| Targets | Touch target at least density.target-min (desktop SC 2.5.8, touch platform value) |
androidTapTargetGuideline, iOSTapTargetGuideline |
| Motion | The system setting "Reduce motion" and the own setting switch to motion.reduced |
Golden test in the context reduced |
| Color | States never only through color; icons differ in shape | Review list in components.md |
| Language | Language of the app set in the semantics tree; agent text without a language tag is not switched | |
| Terminal | The line at the cursor and, on command, the visible screen are readable for screen readers; running output is not read aloud; extra keys bar with labels; the font size follows the system setting and can be set separately in the terminal. How much semantics the renderer xterm provides is not verified [assumed: little]; the build ticket checks it and adds its own semantics layer |
Widget test of the semantics; checklist with VoiceOver, TalkBack, Narrator |
| Visualizations | Every view has a table view with the same values; states with icon and text (25-visualization.md, section 7.4) | Golden and widget tests of bothy_viz |
| Run graph and control room | "As list" shows the run graph as an outline with tree semantics (level, position, state as text, duration, cost) and the control room as the rows of D10; the end of a node and state changes are announced politely under the rule "Live content"; reduced motion: nodes appear without animation (addendum of 2026-10-24) | Semantics snapshots and widget tests of bothy_viz; golden test in the context reduced |
Known risk: according to an internal preliminary study, the accessibility of Flutter on macOS was being reworked [assumed, not checked ourselves]; it is checked with VoiceOver before the first macOS release (ticket in 15-client-architecture.md).
9. Languages¶
- German (default) and English. The language follows
users.locale; the app starts in the system language as long as the person has not chosen one. - Texts in ARB files in
packages/l10n(app_de.arb,app_en.arb), generated withflutter gen-l10n; plurals and select through ICU messages. A missing translation breaks the build. - A test over the ARB files rejects en and em dashes (U+2013, U+2014) and emoji.
- Errors come from the server as a code (RFC 9457, 06-api.md); the app translates the code. Unknown codes show a generic text plus the code.
- Agent content is not translated.
- Numbers, dates and currencies follow the locale of the app (for example "1,84 USD" (de) or "USD 1.84" (en)).
- Terms are fixed so that DE and EN mean the same:
| German | English | Code |
|---|---|---|
| Bereich | Space | space |
| Kanal | Channel | channel |
| Forum, Beitrag | Forum, Post | forum, thread |
| Thread | Thread | thread |
| Erledigt | Done | closed |
| Live-Box | Live box | run |
| Lauf | Run | run |
| Nachtrag | Follow-up | followup |
| Bediener | Operator | operator |
| Freigabe | Access grant | grant |
| Agenten auslösen (Stufe) | Trigger agents | trigger |
| Aktionen freigeben | Approve actions | approve_actions |
| Persönlich, Organisation | Personal, Organization | personal, organization |
| Schätzung | Estimate | cost_is_estimate |
| Rechner | Host | host |
| Host-Dienst | Host service | bothy-host |
| Kopplung, Kopplungs-Code | Pairing, pairing code | host.pair |
| Fingerabdruck | Fingerprint | key_fingerprint |
| Terminal-Sitzung | Terminal session | terminal_session |
| Trennen, Wiederanhängen | Detach, reattach | detached, terminal.attach |
| Sondertasten-Leiste | Extra keys bar | |
| LLM-Anmeldung | LLM login | llm_credentials |
| Live-Topologie | Live topology | |
| TV-Modus | TV mode | |
| Eigene Messung | Own measurement | stats_minutes |
Implementation in packages/l10n (M4-06, docs/DECISIONS.md D-M4-06-1 to D-M4-06-7):
app_en.arbis the template offlutter gen-l10nand German is the default locale (supportedLocaleslistsdefirst). Every message has an@keywith adescription.- Problem codes: each code of
x-problem-codesindocs/api/openapi.yamlhas the messageproblem<Code>(for exampleproblemNotFound); a reason that 07 names selectsproblem<Code><Reason>(for exampleproblemForbiddenCapabilityMissing). Any other code showsproblemFallbackwith the code: "Something went wrong ({code})" or "Etwas ist schiefgegangen ({code})". - The table above is the source of
packages/l10n/lib/src/term_table.dart, generated bypackages/l10n/tool/term_table.dart; a test fails when the generated file is stale and when an English message uses a term of the table while the German message of the same key lacks the German term (direction English to German). - The language gate of the repository excludes the German product strings by path:
packages/l10n/lib/l10n/app_de.arband the generatedpackages/l10n/lib/src/generated/app_localizations_de.dartintools/docs/language-allow.txt.
10. Notifications¶
10.1 When a notification arrives¶
Normative for kinds, recipients, effective level and quiet hours is 13-push-notifications.md, sections 2 to 4. For the interface, in short:
| Event | Level all |
Level mentions |
Level mute |
|---|---|---|---|
| New message in a visible thread (not your own) | yes | no | no |
| Mention of me, message in my direct message | yes | yes | no |
A run that I triggered is waiting for me (waiting_input) |
yes | yes | yes |
| A run that I triggered is finished or has failed | yes | yes | no |
| Messages from agents without a mention | yes | no | no |
Imported or silent messages (silent) |
no | no | no |
During quiet hours notifications arrive silently (no sound, no waking up); counters and badges
keep counting. Only a question from one's own run stays loud, and only if the person has turned on
notify.input_needed_breaks_quiet_hours. Every notification passes through push.deliver
beforehand.
10.2 Content¶
The push itself carries only IDs and a neutral placeholder ("New message"). The app fetches the
text itself (15, background behavior) and then shows
"notify.preview_mode (full, names, none); with none the app never fetches
text. A local notification of the running app then shows the placeholder with the channel name
the app knows locally; a push on iOS and macOS shows the placeholder without a channel name,
because its Notification Service Extension cannot read the encrypted database and a list of
names in its shared container would be content outside it (docs/decisions.d/M5-04.md).
10.3 Platform¶
| Platform | Behavior |
|---|---|
| iOS, macOS | Grouping per thread; tapping opens the thread at the message; badge = unread mentions plus questions |
| Android | Notification channels "Mentions", "Questions", "All messages", "Runs", changeable in the system settings; grouping per thread |
| Windows | The app in the notification area keeps the connection and shows local notifications; a closed app gets no notifications (Baseline R-Push) |
| all | If the thread is currently open and the app is in the foreground, there is no notification, only the history |
Reading on one device removes notifications on the others as soon as that app is active the next time; a separate push only for cleanup is to be checked later.
11. Personal settings¶
Synchronized via user_settings (04 section 14). This table is
normative for all personal keys except notify.* (03-data-model.md,
user_settings); the keys notify.* are in
13-push-notifications.md, section 3.3. The server rejects
unknown keys and values outside the list.
| Key | Values | Default | Meaning |
|---|---|---|---|
appearance.theme |
system, light, dark |
system |
Theme; system follows the device |
appearance.density |
comfortable, compact |
comfortable |
desktop only; mobile fixed to touch |
appearance.reduce_motion |
system, on, off |
system |
Reduce motion |
composer.enter_sends |
true, false |
without a stored value true on desktop and false on mobile; a stored value applies on all devices |
Enter sends |
privacy.crash_reports |
true, false |
true if the instance has set up a crash service |
Send crash reports |
privacy.client_metrics |
true, false |
true |
Send performance data without content |
layout.column_widths |
Object: names ^[a-z][a-z0-9_]*$ (column, for example sidebar, post_list, session), values non-negative integers in logical pixels |
empty | Column widths on desktop; the client interprets the names |
12. Branding per instance¶
Two layers (ADR 0044):
| Layer | What | Where defined | Effect |
|---|---|---|---|
| Runtime | Product name, logo, accent | instance_settings: branding.product_name, branding.logo_file_id, branding.accent_color (action instance.branding.update) |
App and console show name and logo; the accent replaces color.accent.* |
| Build | App name in the system, bundle and package IDs, app icons, URL scheme for deep links and login, push topics (APNs topic = bundle ID, Firebase project), update feeds (Sparkle, .appinstaller), signing identities, default server address |
File branding.yaml of the instance (lives in the instance operator's repo, not in the product), read by the build |
Own signed app per instance |
Rules:
branding.accent_coloris a key from the category colors (spruce,loch,heather,rowan,amber,gorse,moss), not a free color value; only these combinations are in the contrast test (03,instance_settings; schema in the configuration reference). Every variant of these accents, in light and dark, is in the contrast table (contrast.md); the design generator fails when one falls below AA.- Without its own build configuration, the repo builds a neutral version with the working name
and placeholder IDs under
example.com. - The logo is uploaded as a file and served only through the server; the app falls back to the product's mark as long as the logo is missing.
branding.product_namehas at mostbranding.product_name_max_charscharacters (03) and no control or bidi characters (19-security.md, SEC-IN-4).
13. Decisions of this chapter¶
| No. | Decision | Reason |
|---|---|---|
| R-PR-01 | Four columns on desktop; post list only for forums; the right column shows the session instead of members. | Study B; member lists are of no use in agent work, session data is. |
| R-PR-02 | Presence only for agents, never for people. | Privacy and co-determination; for agents, presence is operational information. |
| R-PR-03 | No read receipts for others; the read state stays personal. | Avoid performance monitoring; not in the baseline scope. |
| R-PR-04 | No keyboard shortcut triggers an approval. | Operating errors on approvals are expensive. |
| R-PR-05 | Questions from one's own runs notify even at level "mute" (13, kind input_needed). |
A waiting agent blocks the work of the person who started it. |
| R-PR-06 | Quiet hours make notifications silent; only a question from one's own run becomes loud, if the person turns this on themselves (13). | Reliability before urgency; the only exception is in the hands of the person. |
| R-PR-07 | On mobile there are emergency actions of the administration, not the whole administration. | Small screens for complex permissions are error-prone; but disabling and revoking must work on the go. |
| R-PR-08 | Accent per instance only from the checked palette. | Contrast AA is a test, not a hope. |
| R-PR-09 | Link preview in the client only later and only with opt-in. | The server loads no foreign URLs; the client would contact foreign servers. |
| R-PR-10 | In the terminal all keys go to the shell; app shortcuts only with Cmd (macOS) or Ctrl+Shift (Windows). | Shells and coding agents use Ctrl and Alt; a swallowed Ctrl+C would be an operating error with consequences. |
| R-PR-11 | On mobile, an extra keys bar with one-shot modifiers instead of a custom keyboard. | The system keyboard stays (dictation, languages, accessibility); only the keys that a shell needs are missing. |
| R-PR-12 | The app detaches the terminal when it moves to the background and hides it in the app switcher. | Mobile systems end connections in the background anyway; the image in the app switcher would show terminal content. |
| R-PR-13 | Product description "Command center for AI agents in chat form" with six pillars (chat, live view, grants, terminal, costs, statistics). | Requirement of the owner (addendum of 2026-10-10); it determines the home page, docs and showcase. |
| R-PR-14 | Onboarding screens E1 to E7 shared by all apps; before login only the branding of the instance; with an invalid certificate no continue and no exception button. | One flow for all platforms keeps the security rules from 08 in one place; an exception button would let an attacker in the middle defeat DPoP and device binding. |
| R-PR-15 | The run graph is an indented trace view on a time axis, not a node-link diagram, on desktop, iPhone and Android; not in the web console (addendum of 2026-10-24). | Tree and time stay readable together, the layout does not jump when nodes arrive, it scales with a virtualized list and works on a phone; the console has no run views (ADR 0028). |
| R-PR-16 | The control room is "Running now" with cards and stays in its place; cards visible on the screen are live through focus, the others show the summary (addendum of 2026-10-24). |
One place and one permission for active runs; live data only where a person looks, within the existing focus limit. |
14. Configuration values of this chapter¶
| Name | Default | Meaning |
|---|---|---|
ui.message_group_window |
5m |
messages of the same author within this time get no header of their own |
ui.message_collapse_lines |
24 |
from this many lines on, a message is collapsed |
ui.livebox_visible_steps |
6 |
visible steps in the running live box |
ui.composer_max_lines |
12 |
the input grows up to this many lines |
ui.autocomplete_debounce |
150ms |
waiting time before command.autocomplete |
ui.quick_switch_max_results |
20 |
hits in the quick switcher |
ui.desktop_min_width_four_columns |
1280px |
below this width the session column collapses |
ui.desktop_min_width_three_columns |
960px |
below this width the post list becomes a stack |
a11y.live_announce_min_interval |
10s |
the live box announces a change at most this often |
client.share.recent_targets |
8 |
recently used targets in the share sheet |