Skip to content
Draft
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
74 changes: 69 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ authors = ["octos-app contributors"]
octosense-updater-ui = { path = "crates/updater-ui" }
rinx = { git = "https://github.com/hagency-org/Rinx.git", tag = "v1.1.0", default-features = false, features = ["octosense-module"] }
octosense-reference = { path = "apps/reference" }
octosense-octobuddy = { git = "https://github.com/tyreseluo/OctoBuddy.git", rev = "668765cc3e1e6c2ccd9a35baaeabebd76d3da852", default-features = false, features = ["octosense-module"] }
makepad-sheets = { git = "https://github.com/OctoSense-org/makepad.git", rev = "d653bc4493619ab979ccff165cf48c0c63b77d19", default-features = false }
makepad-terminal = { git = "https://github.com/OctoSense-org/makepad.git", rev = "d653bc4493619ab979ccff165cf48c0c63b77d19" }
octosense-appcard = { path = "apps/appcard/module" }
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ These apps have an agent:
| App | Kind | Its agent's own tools | What the system agent may call |
| --- | --- | --- | --- |
| Rinx (Matrix chat) | native, in the shell | octos's file, memory and web tools | – |
| OctoBuddy (desktop; [its grants](docs/native-apps/octobuddy.md)) | native, in the shell | its loops' own agents (Claude Code, Codex, pi, octos), checked by the host, and `terminal.run` | `octobuddy.status` (read); `octobuddy.send`, `octobuddy.report` and `octobuddy.request`, each confirmed by the person |
| Terminal (desktop) | native; its own process in a checkout build, inside the shell in a release package | `terminal.read_screen`, `terminal.read_scrollback` | `terminal.run`, only while it runs as its own sandboxed process, behind Setup's switch, approved per command |
| Calculator, Clock, Notes, Reminders, Weather | native, in the shell | each app's read tools | the same read tools |
| App Hub | native, in the shell | `apphub.search`, `apphub.installed`, `apphub.updates`, read only: installs and updates stay on App Hub's own screens | the same read tools |
Expand Down Expand Up @@ -407,6 +408,7 @@ Pinned exactly once, in the root `Cargo.toml` and the runtime locks:
| [OctoSense-App-Hub](https://github.com/OctoSense-org/OctoSense-App-Hub) | The signed catalog, the store, and the Card runner that contains every script app. |
| [octos](https://github.com/octos-org/octos) | The agent kernel. Android bundles it in the APK as `liboctos.so`; the desktop runs the packaged `octos-kernel` beside the shell, checked against this revision (`tools/kernel-artifact.py --host --stage` builds it). |
| [Rinx](https://github.com/hagency-org/Rinx) | Matrix chats and mini apps, hosted as a native module. |
| [OctoBuddy](https://github.com/tyreseluo/OctoBuddy) | The coding app: an outer loop plans the work into slices, inner loops build them in parallel, and the host checks and reviews what lands. Hosted as a native module on the desktop. |
| [OctosCode](https://github.com/octos-org/octoscode-app) | The coding client of the person's assistant, hosted as a native module that reaches the kernel through its port in the coding scope (ADR 0003, item 9). |

Related, not build inputs: [OctoSense-App-Flow](https://github.com/OctoSense-org/OctoSense-App-Flow) (how apps are built and published), [OctoScript-Android](https://github.com/OctoSense-org/OctoScript-Android) and [OctoScript-OH](https://github.com/OctoSense-org/OctoScript-OH) (other renderers), the [OctoSense website](https://github.com/OctoSense-org/octosense-org.github.io).
Expand Down
2 changes: 2 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ flowchart LR
| 应用 | 类型 | 它的 Agent 自己的工具 | 系统 Agent 可以调用 |
| --- | --- | --- | --- |
| Rinx(Matrix 聊天) | 原生,在 Shell 内 | octos 的文件、记忆和网页工具 | – |
| OctoBuddy(桌面;[授权说明](docs/native-apps/octobuddy.zh-CN.md)) | 原生,在 Shell 内 | 它双环自己驱动的 agent(Claude Code、Codex、pi、octos),由宿主检查验收,另有 `terminal.run` | `octobuddy.status`(只读);`octobuddy.send`、`octobuddy.report` 与 `octobuddy.request`,每次都经人确认 |
| Terminal(桌面端) | 原生;源码检出构建中为独立进程,发布包中在 Shell 内 | `terminal.read_screen`、`terminal.read_scrollback` | `terminal.run`,只在它作为独立的沙箱进程运行时提供,受 Setup 开关控制,每条命令都要批准 |
| Calculator、Clock、Notes、Reminders、Weather | 原生,在 Shell 内 | 各自的只读工具 | 同样的只读工具 |
| App Hub | 原生,在 Shell 内 | `apphub.search`、`apphub.installed`、`apphub.updates`,只读:安装和更新仍在 App Hub 自己的界面上进行 | 同样的只读工具 |
Expand Down Expand Up @@ -395,6 +396,7 @@ Shell 只有一份,位于 `crates/shell`([ADR 0001(英文)](docs/adr/000
| [OctoSense-App-Hub](https://github.com/OctoSense-org/OctoSense-App-Hub) | 签名目录、商店,以及隔离运行每个脚本应用的 Card runner。 |
| [octos](https://github.com/octos-org/octos) | Agent 内核。Android 上 APK 以 `liboctos.so` 形式内置它;桌面端运行 Shell 旁随附的 `octos-kernel`,并核对其版本与此处固定的一致(由 `tools/kernel-artifact.py --host --stage` 构建)。 |
| [Rinx](https://github.com/hagency-org/Rinx) | Matrix 聊天与小程序,作为原生模块托管。 |
| [OctoBuddy](https://github.com/tyreseluo/OctoBuddy) | 编码应用:外环把工作拆成切片,inner 并行实现,宿主检查验收。桌面端作为原生模块托管。 |
| [OctosCode](https://github.com/octos-org/octoscode-app) | 用户助手的编码客户端,作为原生模块托管,经由编码范围内的内核端口访问内核(ADR 0003 第 9 条)。 |

相关但不参与构建:[OctoSense-App-Flow](https://github.com/OctoSense-org/OctoSense-App-Flow)(如何构建和发布应用)、[OctoScript-Android](https://github.com/OctoSense-org/OctoScript-Android) 和 [OctoScript-OH](https://github.com/OctoSense-org/OctoScript-OH)(其他渲染后端)、[OctoSense 网站](https://github.com/OctoSense-org/octosense-org.github.io)。
Expand Down
1 change: 1 addition & 0 deletions crates/ai-host/src/native_agents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
/// (app id, the `octos.*` services its agent is granted).
pub const NATIVE_AGENTS: &[(&str, &[&str])] = &[
("rinx", &["octos.session.open", "octos.session.history", "octos.turn.start", "octos.turn.interrupt"]),
("octobuddy", &["octos.session.open", "octos.session.history", "octos.turn.start", "octos.turn.interrupt"]),
("sheets", &["octos.session.open", "octos.session.history", "octos.turn.start", "octos.turn.interrupt"]),
("terminal", &["octos.session.open", "octos.session.history", "octos.turn.start", "octos.turn.interrupt"]),
("apphub", &["octos.session.open", "octos.session.history", "octos.turn.start", "octos.turn.interrupt"]),
Expand Down
2 changes: 2 additions & 0 deletions crates/shell/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ makepad-aichat = { workspace = true, optional = true }
octosense-updater-ui = { workspace = true, optional = true }
rinx = { workspace = true, features = ["octosense-module"], optional = true }
octosense-reference = { workspace = true, optional = true }
octosense-octobuddy = { workspace = true, features = ["octosense-module"], optional = true }
makepad-sheets = { workspace = true, optional = true }
makepad-terminal = { workspace = true, optional = true }
octosense-appcard = { workspace = true, optional = true }
Expand Down Expand Up @@ -179,6 +180,7 @@ mobile-apps = ["app-updater", "app-rinx", "app-reference", "app-sheets", "app-hu
app-updater = ["dep:octosense-updater-ui"]
app-rinx = ["dep:rinx", "octos-core"]
app-reference = ["dep:octosense-reference"]
app-octobuddy = ["dep:octosense-octobuddy"]
app-sheets = ["dep:makepad-sheets"]
app-terminal = ["dep:makepad-terminal"]
app-appcard = ["dep:octosense-appcard", "octos-core"]
Expand Down
6 changes: 5 additions & 1 deletion crates/shell/src/approvals/sheet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,13 @@ pub struct Sheet {
pub opened: u64,
}

/// `os.mail` → `Mail`.
/// `os.mail` → `Mail`; a native app's `name` where it declares one
/// (`octobuddy` → `OctoBuddy`).
pub fn app_label(app: &str) -> String {
let id = app.strip_prefix("os.").unwrap_or(app);
if let Some(name) = crate::native_apps::find(id).and_then(|native| native.name) {
return name.to_string();
}
let mut chars = id.chars();
match chars.next() {
Some(c) => c.to_uppercase().collect::<String>() + chars.as_str(),
Expand Down
8 changes: 8 additions & 0 deletions crates/shell/src/approvals/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1176,3 +1176,11 @@ fn settings_lists_every_app_that_declares_an_agent_before_it_asks() {
assert!(listed.contains(&("org.example.trip".to_string(), State::Undecided)), "listed before it ever asked: {listed:?}");
let _ = std::fs::remove_dir_all(&dir);
}

#[test]
fn a_native_apps_declared_name_is_what_its_sheets_say() {
use super::sheet::app_label;
assert_eq!(app_label("octobuddy"), "OctoBuddy", "native-apps.json's name");
assert_eq!(app_label("rinx"), "Rinx", "no name: the id with a capital");
assert_eq!(app_label("os.mail"), "Mail");
}
46 changes: 46 additions & 0 deletions crates/shell/src/native_apps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ pub enum KernelPort {
#[derive(Debug)]
pub struct NativeApp {
pub id: &'static str,
/// What the person sees (`name`); none: the id with a capital.
pub name: Option<&'static str>,
/// The shell's Cargo feature that links it.
pub feature: &'static str,
/// The binary a process-hosted instance runs.
Expand Down Expand Up @@ -116,6 +118,7 @@ pub struct NativeApp {
pub const APPS: &[NativeApp] = &[
NativeApp {
id: "updater",
name: None,
feature: "app-updater",
bin: None,
macos: Hosting::Module,
Expand Down Expand Up @@ -143,6 +146,7 @@ pub const APPS: &[NativeApp] = &[
},
NativeApp {
id: "rinx",
name: None,
feature: "app-rinx",
bin: None,
macos: Hosting::Module,
Expand Down Expand Up @@ -170,6 +174,7 @@ pub const APPS: &[NativeApp] = &[
},
NativeApp {
id: "reference",
name: None,
feature: "app-reference",
bin: Some("octosense-reference"),
macos: Hosting::Module,
Expand All @@ -195,8 +200,37 @@ pub const APPS: &[NativeApp] = &[
calls_per_day: None,
kernel: KernelPort::None,
},
NativeApp {
id: "octobuddy",
name: Some("OctoBuddy"),
feature: "app-octobuddy",
bin: None,
macos: Hosting::Module,
windows: Hosting::Module,
linux: Hosting::Module,
android: Hosting::Module,
ios: Hosting::Module,
ohos: Hosting::Module,
wasm: Hosting::Module,
octos: &["octos.session.open", "octos.session.history", "octos.turn.start", "octos.turn.interrupt"],
tools: &[],
network: Network::Any,
processes: true,
accounts: false,
external: &[],
storage: r#"{"accounts": false, "agent_workspace": "account", "external": []}"#,
tools_json: r##"[{"name":"octobuddy.status","description":"What OctoBuddy is doing now: its projects and sessions, each session's outer loop (what it does, its cost, what waits for it) and its inner loops (role, status, estimate and steps used, cost, the outer loop's verdict). Its published apps as its Live page has them (live.apps: each app's published version, whether it is watched and its health, an open incident with what is wrong and what was done, the last report). Optionally only one project, by name.","input_schema":{"type":"object","properties":{"project":{"type":"string","maxLength":200}},"additionalProperties":false},"risk":"read","shareable":true},{"name":"octobuddy.send","description":"Send a message to the outer loop of one OctoBuddy session, as the person would from its composer; it waits in the session's queue while the outer loop is busy. The session is named by its id or by words of its title.","input_schema":{"type":"object","properties":{"session":{"type":"string","maxLength":200},"message":{"type":"string","minLength":1,"maxLength":8000}},"required":["session","message"],"additionalProperties":false},"risk":"act","confirm":"host","shareable":true},{"name":"octobuddy.report","description":"Report a problem with an app OctoBuddy built and published (the person says it is broken, or another app saw it fail). Call it first, before checking anything yourself: OctoBuddy runs the published version on this device at once (no need to fetch its API or run anything) and keeps watching it; the reply says whether that run found the problem and what was on screen, and the app's OctoBuddy session hears it. Repairing it stays the person's choice in OctoBuddy (its Live page). The app is named by its name or id.","input_schema":{"type":"object","properties":{"app":{"type":"string","minLength":1,"maxLength":200},"problem":{"type":"string","minLength":1,"maxLength":2000},"from":{"type":"string","maxLength":200}},"required":["app","problem"],"additionalProperties":false},"risk":"act","confirm":"host","shareable":true},{"name":"octobuddy.request","description":"Ask OctoBuddy for a new OctoSense app (the person wants one, or another app needs one). It waits for the person: OctoBuddy shows it on its Apps page and builds it only if they press Build (an outer loop plans it, inner loops make it, its check runs); they publish it to the local App Hub from there. The reply is at once, with the request's id; octobuddy.status shows its status under requests. Say what it is for, what it shows and does, and when it is done; name its data (an https JSON API) if it has one.","input_schema":{"type":"object","properties":{"what":{"type":"string","minLength":1,"maxLength":4000},"for":{"type":"string","maxLength":200},"acceptance":{"type":"string","maxLength":2000},"data":{"type":"string","maxLength":500},"name":{"type":"string","maxLength":60}},"required":["what"],"additionalProperties":false},"risk":"act","confirm":"host","shareable":true}]"##,
generic_tools: &["read_file", "write_file", "edit_file", "glob", "grep", "list_dir", "web_search", "web_fetch", "view_image", "ask_user_question", "memory_search", "save_memory"],
grants: &[("terminal", "terminal.run")],
system_tools: &[],
own_tools: &["octobuddy.status", "octobuddy.send", "octobuddy.report", "octobuddy.request"],
calls_per_turn: None,
calls_per_day: None,
kernel: KernelPort::None,
},
NativeApp {
id: "sheets",
name: None,
feature: "app-sheets",
bin: Some("sheets"),
macos: Hosting::Module,
Expand Down Expand Up @@ -224,6 +258,7 @@ pub const APPS: &[NativeApp] = &[
},
NativeApp {
id: "terminal",
name: None,
feature: "app-terminal",
bin: Some("terminal"),
macos: Hosting::Process,
Expand Down Expand Up @@ -253,6 +288,7 @@ pub const APPS: &[NativeApp] = &[
},
NativeApp {
id: "appcard",
name: None,
feature: "app-appcard",
bin: None,
macos: Hosting::Module,
Expand Down Expand Up @@ -280,6 +316,7 @@ pub const APPS: &[NativeApp] = &[
},
NativeApp {
id: "apphub",
name: None,
feature: "app-hub",
bin: None,
macos: Hosting::Module,
Expand Down Expand Up @@ -307,6 +344,7 @@ pub const APPS: &[NativeApp] = &[
},
NativeApp {
id: "calculator",
name: None,
feature: "app-calculator",
bin: Some("calculator"),
macos: Hosting::Module,
Expand Down Expand Up @@ -334,6 +372,7 @@ pub const APPS: &[NativeApp] = &[
},
NativeApp {
id: "clock",
name: None,
feature: "app-clock",
bin: Some("clock"),
macos: Hosting::Module,
Expand Down Expand Up @@ -361,6 +400,7 @@ pub const APPS: &[NativeApp] = &[
},
NativeApp {
id: "notes",
name: None,
feature: "app-notes",
bin: Some("notes"),
macos: Hosting::Module,
Expand Down Expand Up @@ -388,6 +428,7 @@ pub const APPS: &[NativeApp] = &[
},
NativeApp {
id: "reminders",
name: None,
feature: "app-reminders",
bin: Some("reminders"),
macos: Hosting::Module,
Expand Down Expand Up @@ -415,6 +456,7 @@ pub const APPS: &[NativeApp] = &[
},
NativeApp {
id: "weather",
name: None,
feature: "app-weather",
bin: Some("weather"),
macos: Hosting::Module,
Expand Down Expand Up @@ -442,6 +484,7 @@ pub const APPS: &[NativeApp] = &[
},
NativeApp {
id: "octoscode",
name: None,
feature: "app-octoscode",
bin: None,
macos: Hosting::Module,
Expand Down Expand Up @@ -469,6 +512,7 @@ pub const APPS: &[NativeApp] = &[
},
NativeApp {
id: "task",
name: None,
feature: "app-task",
bin: Some("task"),
macos: Hosting::Process,
Expand Down Expand Up @@ -556,6 +600,8 @@ pub fn link(out: &mut Vec<&'static dyn AppModule>) {
out.push(&rinx::module::RINX_MODULE);
#[cfg(any(feature = "app-reference", native_mobile))]
out.push(&octosense_reference::REFERENCE_MODULE);
#[cfg(feature = "app-octobuddy")]
out.push(&octosense_octobuddy::OCTOBUDDY_MODULE);
#[cfg(any(feature = "app-sheets", native_mobile))]
out.push(&makepad_sheets::SHEETS_MODULE);
#[cfg(feature = "app-terminal")]
Expand Down
1 change: 1 addition & 0 deletions crates/shell/src/sandbox/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ impl Drop for Scratch {
fn jail_only(root: &Path, hub_port: u16) -> Policy {
let app = crate::native_apps::NativeApp {
id: "probe",
name: None,
feature: "app-probe",
bin: Some("probe"),
macos: crate::native_apps::Hosting::Process,
Expand Down
Loading