Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CONTEXT.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# Personal robot registration

A non-executable record in the profile-scoped store implemented by
`raven.ops.robots.RobotStore`, exposed through `robots.*` RPC methods. It is
separate from the machine registry and its SSH/Raven nodes. Only confirmed
personal records are supported; optional status checks are explicit, bounded
GET requests and expire after 60 seconds. Registration or a reachable status
endpoint is not acceptance of physical robot capabilities. See
`docs/robot-registration.md` for the storage and network boundaries.

# Raven Runtime

The Python agent runtime: receives messages from chat channels, runs the agent loop
Expand Down
55 changes: 55 additions & 0 deletions docs/robot-registration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Personal robot registrations

The Connections hub separates **Machines**, where Raven may run an agent through
its existing SSH/node support, from **Robots**, which are device records without
an execution node. Existing machine IDs, configuration, SSH credentials, CLI
commands, `machines.*` methods, and the Machines label are unchanged.

The Robots tab supports adding, searching, filtering, editing, moving records to
trash, and restoring them. Registration does not establish a connection.
Company devices and credentials are out of scope: the form blocks company
registration, and the runtime accepts only explicitly confirmed personal records.
Use independently governed instances for other security domains rather than
mixing their data into the personal registry.

## Optional read-only status

SparkBot and generic HTTP devices can have a status URL. Robot dogs, AGVs, mobile
manipulators, and other device types support metadata only. No robot is treated
as a Machine and no executable node is installed.

Only **Check status** contacts a device. It sends one GET, without credentials,
proxies, or redirects, to a literal RFC1918 IPv4 address whose path is `/health`
or `/status`. Ports are limited to 80, 443, or 1024-65535. DNS names, public,
loopback, and link-local addresses, credentials, query parameters, and fragments
are rejected. The timeout is three seconds and the uncompressed JSON response limit is 16 KiB.
Compressed responses and non-standard numeric constants are rejected.
An optional expected `project` value prevents accepting a different device.
Only a bounded allowlist of health fields is retained.

The states are unknown, not connected, error, and status endpoint reachable.
`ok: true` confirms the status endpoint only: it does not establish chassis,
audio, or motion acceptance. Results expire after 60 seconds, including when a
page remains open. Failed and malformed responses are never shown as online.
There is no scanning or background device polling and no control, shell, ROS,
MQTT, motion, or media endpoint.

## Persistence and compatibility

The existing authenticated RPC transport serves `robots.list`, `robots.save`,
`robots.remove`, `robots.restore`, and `robots.check`. Web clients use the same
typed transport and source seam as the other hub tabs. An older gateway without
these methods produces an unavailable message rather than invented records.
Offline fixtures never contact a real device or claim it is connected.

Records live under `robots/<config-stem>/personal/devices.sqlite3` beside the
resolved configuration file. Separate configuration files have separate stores;
the default is therefore under the instance's Raven home. The directory is
owner-only and the database is owner-readable/writable on POSIX. Records are
limited to 100, including trash. Removal is recoverable; restoring or editing a
record clears its old health observation. Revisions prevent a stale editor or
an overlapping health request from overwriting a later edit or removal.

The feature does not modify the Machine registry or model/provider configuration.
Reverting the code leaves the separate database intact and stops exposing the
tab and RPC methods. Reapplying the feature reopens those registrations.
53 changes: 52 additions & 1 deletion i18n/messages.json

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: the GUI relabels the canonical Machine concept as "Servers" (zh: the word for "server"), which is the word CONTEXT.md's Machine entry rules out. CONTEXT.md is left unchanged, so it now contradicts the page.

What changed.

  • gui.hub.machines goes from {"en": "Machines", "zh": <"machine">} to {"en": "Servers", "zh": <"server">} (i18n/messages.json:3410).
  • The gui.machine.* block and its neighbours are reworded to "server" (for example "No server is registered; see the Servers tab."). The catalogue's count of the zh word for "server" goes from 14 to 56.
  • The PR's own new text uses the same word: ui-web/CONTEXT.md ("not server registrations"), docs/robot-registration.md ("separates Servers, where Raven may run an agent", "No robot is treated as a server"), and ui-web comments (state/hub.ts, HubHead.tsx, store.ts, manifest.ts).

What CONTEXT.md still says.

  • Machine (CONTEXT.md:403), with _Avoid_: "host" / "server" / "node" (too broad, no link to the ops connection registry that supplies the rows) at :504.
  • ":453 The registry itself is kept from the Agent Hub's Machines tab", which is now false.
  • The model-facing instructions and the server's own refusal text elsewhere still say Machines. So a person sees "Servers" while the agent and the docs say "Machines", and "server" is already used on the same pages for the gateway, MCP servers and mail servers.

Rule. AGENTS.md section 6: naming a concept tracked in CONTEXT-MAP.md means using the canonical term, not a synonym; a new term is defined in the matching CONTEXT.md in the same change.

Fix, either:

  • keep "Machines" (and the zh word for "machine") for the machine registry, and keep the robot work as its own tab and term; or
  • if the product wants the rename, make it a CONTEXT.md decision in this change: rename the entry, move "server" out of Avoid with a reason, fix :453, and update the agent-facing text, so every surface says one word.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: the Machine-to-Server relabel conflicts with the repository canonical terminology.

This newly raised conflict makes my prior clean stance stale. CONTEXT.md defines the registry concept as Machine, explicitly lists server under _Avoid_, and still names the Machines tab, while this revision relabels that same concept throughout the GUI and new documentation without changing the canonical definition. Until the author either keeps Machine or makes the product rename consistent in the canonical context and affected surfaces, I no longer consider this revision mergeable. This is a stance update based on the existing thread, not a separate finding.

No code has changed since the already reported test run; this objection is the repository term-contract mismatch itself.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blockers; this can merge as far as I am concerned.

My terminology objection is settled on daeee4b3ae79: the existing execution-host concept is again Machines in the catalogue, generated text, documentation, RPC module description, and UI comments, while Robots remains separate. I found no residual Machine-to-Server relabel in the feature diff.

I am not resolving this review thread because it was opened by another reviewer.

Original file line number Diff line number Diff line change
Expand Up @@ -13160,6 +13160,57 @@
"gui.export.stop_report_label": {
"en": "Discard",
"zh": "放弃"
}
},
"gui.extAgents.robot_title": {"en": "Personal robots", "zh": "个人机器人"},
"gui.extAgents.robot_add": {"en": "Register robot", "zh": "登记机器人"},
"gui.extAgents.robot_edit": {"en": "Edit registration", "zh": "编辑登记"},
"gui.extAgents.robot_name": {"en": "Device name", "zh": "设备名称"},
"gui.extAgents.robot_type": {"en": "Device type", "zh": "设备类型"},
"gui.extAgents.robot_model": {"en": "Model", "zh": "型号"},
"gui.extAgents.robot_location": {"en": "Location", "zh": "位置"},
"gui.extAgents.robot_note": {"en": "Note", "zh": "备注"},
"gui.extAgents.robot_mode": {"en": "Connection mode", "zh": "连接方式"},
"gui.extAgents.robot_metadata": {"en": "Metadata only", "zh": "仅登记信息"},
"gui.extAgents.robot_http": {"en": "Read-only HTTP status", "zh": "HTTP 只读状态"},
"gui.extAgents.robot_status_url": {"en": "Status URL", "zh": "状态地址"},
"gui.extAgents.robot_identity": {"en": "Expected project identity (optional)", "zh": "预期设备标识(可选)"},
"gui.extAgents.robot_url_hint": {"en": "Private IPv4 /health or /status only; no credentials, query parameters, or redirects.", "zh": "仅支持局域网 IPv4 的 /health 或 /status;不接受凭据、查询参数或重定向。"},
"gui.extAgents.robot_domain": {"en": "Security domain", "zh": "安全域"},
"gui.extAgents.robot_personal": {"en": "Personal devices", "zh": "个人设备"},
"gui.extAgents.robot_company": {"en": "Company devices (unsupported here)", "zh": "公司设备(此实例不接收)"},
"gui.extAgents.robot_company_blocked": {"en": "Company devices require a separate governed instance and are not supported by this personal registry.", "zh": "公司设备需要独立的受管实例,此个人登记库不接收公司设备。"},
"gui.extAgents.robot_boundary": {"en": "Personal devices only. Do not enter company addresses, accounts, or credentials. Registration does not establish a connection.", "zh": "只登记个人设备,请勿填写公司地址、账号或凭据。登记不等于已连接。"},
"gui.extAgents.robot_personal_confirm": {"en": "I confirm this is a personal device and contains no company data or credentials.", "zh": "我确认这是个人设备,登记信息不含公司数据或凭据。"},
"gui.extAgents.robot_readonly_confirm": {"en": "I confirm this endpoint only reports status and does not trigger control or motion.", "zh": "我确认此地址只提供状态,不会触发控制或动作。"},
"gui.extAgents.robot_metadata_only": {"en": "This device type supports metadata only; no connection or control is attempted.", "zh": "此设备类型仅支持信息登记,不建立连接或执行控制。"},
"gui.extAgents.robot_safety": {"en": "Check status sends one read-only GET on demand. Results expire after 60 seconds. A reachable endpoint does not verify chassis, audio, or motion. No executable node is installed.", "zh": "仅在点击检查时发送一次只读 GET,结果 60 秒后过期。接口可达不代表底盘、音频或动作能力已验收;不安装执行节点。"},
"gui.extAgents.robot_search": {"en": "Search devices", "zh": "搜索设备"},
"gui.extAgents.robot_filter": {"en": "Filter device types", "zh": "筛选设备类型"},
"gui.extAgents.robot_all_types": {"en": "All types", "zh": "全部类型"},
"gui.extAgents.robot_trash": {"en": "Trash", "zh": "回收站"},
"gui.extAgents.robot_back": {"en": "Back to devices", "zh": "返回设备"},
"gui.extAgents.robot_restore": {"en": "Restore", "zh": "恢复登记"},
"gui.extAgents.robot_remove": {"en": "Move to trash", "zh": "移入回收站"},
"gui.extAgents.robot_check": {"en": "Check status", "zh": "检查状态"},
"gui.extAgents.robot_checking": {"en": "Checking...", "zh": "检查中…"},
"gui.extAgents.robot_checked": {"en": "Last checked", "zh": "最近检查"},
"gui.extAgents.robot_loading": {"en": "Loading registrations...", "zh": "正在读取登记…"},
"gui.extAgents.robot_empty": {"en": "No matching registrations.", "zh": "没有匹配的登记。"},
"gui.extAgents.robot_save_failed": {"en": "Could not save. Check the fields, or refresh if another client edited this record.", "zh": "保存失败。请检查字段;如其他页面已修改此记录,请刷新后重试。"},
"gui.extAgents.robot_operation_failed": {"en": "The operation failed. The device has not been assumed online.", "zh": "操作未完成,未将设备认定为在线。"},
"gui.extAgents.robot_unavailable": {"en": "Robot registration is unavailable on this gateway. Existing registrations have not been changed.", "zh": "此网关的机器人登记暂不可用,原记录未被修改。"},
"gui.extAgents.robot_unverified": {"en": "No verified connection. Registration alone does not establish availability.", "zh": "连接尚未验证,登记不代表设备可用。"},
"gui.extAgents.robot_reachable": {"en": "Status endpoint reachable", "zh": "状态接口可达"},
"gui.extAgents.robot_disconnected": {"en": "Not connected", "zh": "未连接"},
"gui.extAgents.robot_unknown": {"en": "Unknown", "zh": "未知"},
"gui.extAgents.robot_error": {"en": "Error", "zh": "错误"},
"gui.extAgents.robot_sparkbot": {"en": "SparkBot", "zh": "SparkBot"},
"gui.extAgents.robot_http_device": {"en": "HTTP device", "zh": "HTTP 设备"},
"gui.extAgents.robot_dog": {"en": "Robot dog", "zh": "机器狗"},
"gui.extAgents.robot_agv": {"en": "AGV", "zh": "AGV"},
"gui.extAgents.robot_mobile_manipulator": {"en": "Mobile manipulator", "zh": "轮臂"},
"gui.extAgents.robot_other": {"en": "Other device", "zh": "其他设备"},
"gui.hub.robots": {"en": "Robots", "zh": "机器人"},
"gui.page.robots_sub": {"en": "Register personal devices and read status; no executable nodes or robot control.", "zh": "登记个人设备、读取状态;不安装执行节点,不提供机器人控制"}
}
}
Loading