- Introduced a new Chinese version of the README (README_CN.md) to provide localized documentation for AgentOS. - Refactored the NPU bridge to utilize Unix domain sockets instead of HTTP loopback, enhancing security and performance. - Updated the NPU backend to include a server socket configuration, ensuring proper communication over Unix sockets. - Modified the Ntex client to support both network and Unix socket transports, improving flexibility in backend communication. - Adjusted validation logic to enforce the use of Unix sockets for local model endpoints, rejecting loopback HTTP addresses. - Enhanced error messages and documentation throughout the codebase to clarify the new socket-based architecture.
352 lines
15 KiB
Markdown
352 lines
15 KiB
Markdown
# AgentOS
|
|
|
|
[简体中文](README_CN.md)
|
|
|
|
AgentOS is a low-level, Linux-only operating-system agent written in Rust. It
|
|
combines a bounded tool-calling loop with native Linux identities, read-only
|
|
system inspection, durable audit state, Btrfs-backed filesystem history, and
|
|
multiple inference backends—including an in-progress pure-Rust path for a
|
|
CALCULET NPU.
|
|
|
|
> **Development status:** the remote OpenAI-compatible mock path and explicit
|
|
> subprocess/fake test adapters are implemented. Locally deployed model services
|
|
> use Unix domain sockets, never localhost or TCP. The Rust Candle/CALRT host
|
|
> pipeline can parse and validate the captured Qwen3 deployment, but CALRT
|
|
> hardware job submission is not implemented yet. `npu_candle` therefore fails
|
|
> closed and is not production-ready.
|
|
|
|
## Design
|
|
|
|
AgentOS is not a container sandbox or a kernel fork. Its isolation boundary is
|
|
the Linux process identity:
|
|
|
|
- every active `AgentId` is stably bound to an owner UID and a non-root agent
|
|
UID/GID;
|
|
- the runtime verifies the process effective UID/GID before every run;
|
|
- UID 0 or GID 0 agents are rejected;
|
|
- `no_new_privs` is enabled before model/tool execution;
|
|
- the model sees an explicit tool allowlist, never a raw root shell;
|
|
- system mutation is intentionally unavailable until a typed, authenticated
|
|
broker is implemented.
|
|
|
|
The current execution path is:
|
|
|
|
```text
|
|
agentos CLI
|
|
-> runtime + Linux principal
|
|
-> budgeted agent loop
|
|
-> ChatBackend (remote OpenAI-compatible / UDS NPU / in-process Candle)
|
|
-> strict ToolRegistry (read-only Linux tools)
|
|
-> SQLite audit log
|
|
|
|
filesystem state -> WorldlineStore -> Btrfs snapshots or copy fallback
|
|
NPU host path -> Candle/Qwen3 -> CALRT -> PCIe driver ABI
|
|
local model IPC -> Unix domain socket -> OpenAI-compatible HTTP payload
|
|
```
|
|
|
|
## What works today
|
|
|
|
- Provider-neutral `agentos.chat.v1` messages, tools, responses, usage, and
|
|
backend interface.
|
|
- Remote OpenAI-compatible non-streaming Chat Completions and Responses APIs
|
|
over `ntex`, with bounded responses, timeouts, retries, and verified TLS when
|
|
HTTPS is selected.
|
|
- OpenAI-compatible HTTP payloads over an AF_UNIX transport for the local legacy
|
|
llama-server, without a localhost/TCP hop.
|
|
- A JSON stdin/stdout subprocess adapter retained for explicit tests and custom
|
|
bridges; it is not the transport for a persistent local model service.
|
|
- Bounded agent iterations, tool calls, elapsed time, total tokens, parallel
|
|
read-only calls, duplicate call-ID checks, and no-progress/cycle detection.
|
|
- Strict JSON tool schemas, allowlists, argument/output limits, deadlines, and
|
|
hashed audit records.
|
|
- Read-only Linux, package, systemd, journal, and CALCULET NPU inspection.
|
|
- SQLite WAL state, FTS5 memory primitives, immutable principal bindings, and
|
|
append-only agent/tool audit events.
|
|
- Btrfs subvolume/snapshot worldlines with branch, diff, commit, log,
|
|
non-destructive rollback, stale-branch protection, and checkout recovery.
|
|
- Rust representations of CALCULET driver 0.9.0 / ABI 1.0.0, BAR and DMA access,
|
|
Calbin 0.7.6 parsing, memory allocation, tensors, and command encoding.
|
|
- A Candle-based Qwen3 host runner with chat templates, tool-call parsing,
|
|
sampling, prefill/decode contracts, BF16/F32 logits, and vendor tiled-logit
|
|
decoding.
|
|
|
|
## Workspace
|
|
|
|
`agentos-cli` is the only binary crate; it produces two binaries. Every other
|
|
workspace member is a library.
|
|
|
|
| Crate | Type | Responsibility |
|
|
| --- | --- | --- |
|
|
| `agentos-cli` | binary | `agentos` CLI and `agentos-npu-bridge` |
|
|
| `agentos-runtime` | library | configuration and composition root |
|
|
| `agentos-agent` | library | bounded agent loop and audit emission |
|
|
| `agentos-protocol` | library | provider-neutral chat/tool protocol |
|
|
| `agentos-inference` | library | ntex, remote, subprocess, and test backends |
|
|
| `agentos-tools` | library | tool policy, schema validation, approvals, Linux tools |
|
|
| `agentos-core` | library | identities, IDs, events, and shared state types |
|
|
| `agentos-kernel` | library | rustix-backed Linux and Btrfs boundary |
|
|
| `agentos-memory` | library | SQLite memory, audit, and principal state |
|
|
| `agentos-worldline` | library | filesystem branch/commit/rollback history |
|
|
| `agentos-npu` | library | NPU discovery, legacy bridge, Candle assembly |
|
|
| `agentos-candle` | library | Qwen3 host inference and CALRT tensor adapter |
|
|
| `calculet-pcie-abi` | library | captured 64-bit Linux ioctl ABI |
|
|
| `calculet-pcie` | library | safe PCIe device operations |
|
|
| `calculet-calrt` | library | Calbin/runtime/command/tensor implementation |
|
|
|
|
## Requirements
|
|
|
|
- 64-bit Linux. AgentOS itself is Linux-only, and the captured CALCULET ABI has
|
|
only been verified on 64-bit Linux.
|
|
- A current Rust toolchain with Rust 2024 edition support.
|
|
- A C toolchain, `pkg-config`, and OpenSSL development files. SQLite is built
|
|
from the bundled source.
|
|
- Btrfs is recommended for kernel-enforced read-only commit snapshots, but is
|
|
not required for development.
|
|
|
|
On Debian/Ubuntu, the native build dependencies are typically:
|
|
|
|
```bash
|
|
sudo apt install build-essential pkg-config libssl-dev
|
|
```
|
|
|
|
Build both binaries and all libraries:
|
|
|
|
```bash
|
|
cargo build --workspace
|
|
```
|
|
|
|
## Quick start without NPU hardware
|
|
|
|
First inspect the host and backend configuration:
|
|
|
|
```bash
|
|
cargo run -p agentos-cli --bin agentos -- \
|
|
--state-dir target/agentos-state --json doctor
|
|
```
|
|
|
|
Run a deterministic smoke test of the model/tool plumbing. This built-in fake
|
|
requests the real read-only `system_inspect` tool, but it is not the remote mock
|
|
used to substitute for unavailable NPU hardware:
|
|
|
|
```bash
|
|
cargo run -p agentos-cli --bin agentos -- \
|
|
--state-dir target/agentos-state --fake-model --json \
|
|
agent once "Inspect this Linux system"
|
|
```
|
|
|
|
Do not run the agent as root. By default, its principal uses the current real
|
|
UID as owner and the current effective UID/GID as the agent identity.
|
|
|
|
## Remote OpenAI-compatible mock inference
|
|
|
|
Hardware-independent mock testing uses a remote OpenAI-compatible model.
|
|
AgentOS supports either `/chat/completions` or `/responses` under a configured
|
|
API base URL. Both HTTP and HTTPS remote URLs are accepted; HTTPS should be used
|
|
whenever credentials or untrusted networks are involved. Localhost and loopback
|
|
model URLs are rejected because local model services must use UDS.
|
|
|
|
```bash
|
|
export AGENTOS_MODEL_BACKEND=openai_compatible
|
|
export AGENTOS_OPENAI_COMPATIBLE_API_KEY='...'
|
|
export AGENTOS_OPENAI_COMPATIBLE_BASE_URL='https://api.openai.com/v1'
|
|
export AGENTOS_OPENAI_COMPATIBLE_MODEL='your-model'
|
|
export AGENTOS_OPENAI_COMPATIBLE_API='responses' # or chat_completions
|
|
|
|
cargo run -p agentos-cli --bin agentos -- \
|
|
--state-dir target/agentos-state \
|
|
agent once "Summarize the current system state"
|
|
```
|
|
|
|
`OPENAI_API_KEY` is accepted as a fallback. A non-empty credential is currently
|
|
required by the remote adapter. Streaming is not implemented.
|
|
|
|
## Local model transport
|
|
|
|
A persistent model on the same Linux host must expose a filesystem Unix domain
|
|
socket. Do not bind it to localhost, a loopback address, or another TCP address.
|
|
The socket path and its owner/group/mode are part of the OS security boundary.
|
|
|
|
The legacy llama-server already supports this mode when `--host` ends in
|
|
`.sock`. AgentOS carries the familiar OpenAI-compatible HTTP request format over
|
|
AF_UNIX, so this is HTTP message framing over UDS—not HTTP over localhost.
|
|
The pure-Rust Candle backend runs in-process and therefore needs no IPC socket.
|
|
|
|
## Read-only tools
|
|
|
|
| Tool | Availability | Operation |
|
|
| --- | --- | --- |
|
|
| `system_inspect` | always | kernel, uptime, load, memory, root filesystem, OS release |
|
|
| `npu_inspect` | always | CALCULET device nodes, module/sysfs/proc monitor, CALRT library |
|
|
| `package_query` | always | exact package lookup via dpkg, rpm, or pacman |
|
|
| `service_inspect` | configured | bounded `systemctl show` for an allowlisted service |
|
|
| `journal_read` | configured | bounded journal read for an allowlisted service |
|
|
|
|
Enable service tools with an exact comma-separated allowlist:
|
|
|
|
```bash
|
|
export AGENTOS_SERVICE_INSPECT_ALLOWLIST='agentos.service,agentos-npud.service'
|
|
```
|
|
|
|
There are currently no mutation tools. The approval ledger in
|
|
`agentos-tools` is a contract primitive, not a complete privilege broker.
|
|
|
|
## Filesystem worldlines
|
|
|
|
Worldlines provide Git-like filesystem history without patching the kernel.
|
|
On Btrfs, current/branch trees are writable snapshots and commit trees are
|
|
read-only snapshots. Other filesystems use a copy fallback; that fallback does
|
|
not provide kernel-enforced immutability.
|
|
|
|
```bash
|
|
AGENTOS=(cargo run -q -p agentos-cli --bin agentos -- \
|
|
--state-dir target/agentos-state --json worldline)
|
|
|
|
"${AGENTOS[@]}" init
|
|
"${AGENTOS[@]}" branch
|
|
"${AGENTOS[@]}" status
|
|
"${AGENTOS[@]}" log --limit 20
|
|
```
|
|
|
|
`branch` returns a worldline ID and path. Modify that branch tree, then use:
|
|
|
|
```bash
|
|
"${AGENTOS[@]}" diff <worldline-id>
|
|
"${AGENTOS[@]}" commit <worldline-id> --message "describe the change"
|
|
"${AGENTOS[@]}" rollback <commit-id> --message "revert to known state"
|
|
"${AGENTOS[@]}" discard <worldline-id>
|
|
```
|
|
|
|
Rollback creates a new commit and retains history. Worldline operations are
|
|
currently explicit CLI operations; agent runs do not automatically create or
|
|
commit a branch.
|
|
|
|
## NPU paths
|
|
|
|
### Legacy llama-server bridge
|
|
|
|
The legacy `npu` backend executes `agentos-npu-bridge`, which connects only to a
|
|
filesystem Unix domain socket and sends `/v1/chat/completions` over that socket.
|
|
It additionally requires a ready CALCULET device, driver sysfs state, and vendor
|
|
CALRT shared library.
|
|
|
|
```bash
|
|
export AGENTOS_MODEL_BACKEND=npu
|
|
export AGENTOS_NPU_BRIDGE_COMMAND='agentos-npu-bridge'
|
|
export AGENTOS_NPU_SERVER_SOCKET='/run/agentos/npu.sock'
|
|
export AGENTOS_NPU_SERVER_MODEL='agentos-npu'
|
|
# Optional when CALRT is not in a probed system location:
|
|
export AGENTOS_CALRT_LIBRARY='/opt/calculet/lib/libcalrt-linux-x86_64.so'
|
|
```
|
|
|
|
Start the captured llama-server with the same socket path, for example
|
|
`--host /run/agentos/npu.sock`, and restrict access using the socket directory
|
|
and socket ownership/mode. No TCP listener is required.
|
|
|
|
### Pure-Rust Candle/CALRT path
|
|
|
|
The `npu_candle` path replaces the modified llama.cpp host code with Rust:
|
|
|
|
```bash
|
|
export AGENTOS_MODEL_BACKEND=npu_candle
|
|
export AGENTOS_NPU_CALBIN='/path/to/calbin-directory'
|
|
export AGENTOS_NPU_TOKENIZER='/path/to/tokenizer.json'
|
|
export AGENTOS_NPU_DEVICE_INDEX=0
|
|
```
|
|
|
|
`doctor` can parse these files and report the model plan without opening the
|
|
device. For the captured Qwen3 deployment, the host validates a 40,960-token
|
|
context, 151,936 logits, a 151,669-token vocabulary, and masks 267 padded logit
|
|
IDs.
|
|
|
|
This backend is deliberately not ready: `calculet-calrt` can deploy parameters
|
|
and transfer tensors, but `ConfiguredRuntime::submit()` still lacks CCU
|
|
relocation, job launch/completion, and device KV-cache reset. No real NPU result
|
|
has been validated on the current development machine.
|
|
|
|
## Configuration
|
|
|
|
| Variable | Default | Meaning |
|
|
| --- | --- | --- |
|
|
| `AGENTOS_STATE_DIR` | `$XDG_DATA_HOME/agentos` or `~/.local/share/agentos` | SQLite and worldline root |
|
|
| `AGENTOS_MODEL_BACKEND` | `auto` | `auto`, `openai_compatible`, `npu`, `npu_candle`, `subprocess`, `fake` |
|
|
| `AGENTOS_AGENT_ID` | `default-agent` | stable logical agent ID |
|
|
| `AGENTOS_OWNER_UID` | real UID | owning Linux UID |
|
|
| `AGENTOS_AGENT_UID` | effective UID | required execution UID |
|
|
| `AGENTOS_AGENT_GID` | effective GID | required execution GID |
|
|
| `AGENTOS_OPENAI_COMPATIBLE_API_KEY` | `OPENAI_API_KEY` | remote bearer credential |
|
|
| `AGENTOS_OPENAI_COMPATIBLE_BASE_URL` | `https://api.openai.com/v1` | remote compatible API root; no localhost/loopback |
|
|
| `AGENTOS_OPENAI_COMPATIBLE_MODEL` | empty | provider model name |
|
|
| `AGENTOS_OPENAI_COMPATIBLE_API` | `chat_completions` | `chat_completions` or `responses` |
|
|
| `AGENTOS_OPENAI_COMPATIBLE_MAX_RETRIES` | `2` | bounded HTTP retries |
|
|
| `AGENTOS_MODEL_COMMAND` | empty | explicit subprocess test/bridge command |
|
|
| `AGENTOS_MODEL_TIMEOUT_S` | `240` | model/bridge timeout |
|
|
| `AGENTOS_NPU_BRIDGE_COMMAND` | empty | legacy NPU bridge command |
|
|
| `AGENTOS_NPU_SERVER_SOCKET` | `/run/agentos/npu.sock` | legacy llama-server Unix socket |
|
|
| `AGENTOS_NPU_SERVER_MODEL` | `agentos-npu` | legacy llama-server model name |
|
|
| `AGENTOS_NPU_SERVER_TIMEOUT_S` | `240` | legacy llama-server UDS HTTP timeout |
|
|
| `AGENTOS_NPU_CALBIN` | empty | pure-Rust Calbin directory |
|
|
| `AGENTOS_NPU_TOKENIZER` | empty | pure-Rust tokenizer JSON |
|
|
| `AGENTOS_NPU_DEVICE_INDEX` | `0` | `/dev/calculetN` index |
|
|
| `AGENTOS_CALRT_LIBRARY` | probed | vendor CALRT shared library override |
|
|
| `AGENTOS_SERVICE_INSPECT_ALLOWLIST` | empty | enabled systemd service names |
|
|
| `AGENTOS_TOOL_OUTPUT_LIMIT_BYTES` | `65536` | per-tool serialized output limit |
|
|
| `AGENTOS_TOOL_ARGUMENT_LIMIT_BYTES` | `65536` | per-call argument limit |
|
|
| `AGENTOS_AGENT_MAX_ITERATIONS` | `8` | model/tool loop turns |
|
|
| `AGENTOS_AGENT_MAX_TOOL_CALLS` | `16` | total tool calls per run |
|
|
| `AGENTOS_AGENT_MAX_ELAPSED_S` | `120` | total run deadline |
|
|
| `AGENTOS_AGENT_MAX_OUTPUT_TOKENS` | `2048` | model output budget per turn |
|
|
| `AGENTOS_AGENT_MAX_TOTAL_TOKENS` | `65536` | cumulative token budget |
|
|
| `AGENTOS_AGENT_MAX_SAFE_WORKERS` | `4` | parallel safe-tool workers |
|
|
|
|
In `auto` mode, AgentOS selects the UDS-backed legacy NPU and then the remote
|
|
OpenAI-compatible backend. Subprocess and fake are explicit test adapters. The
|
|
incomplete Candle backend is not selected automatically.
|
|
|
|
## State layout
|
|
|
|
```text
|
|
AGENTOS_STATE_DIR/
|
|
agentos.sqlite3 # principals, audit events, memory, FTS index
|
|
worldline/
|
|
current/ # active filesystem tree
|
|
branches/ # writable candidate trees
|
|
commits/ # commit trees
|
|
metadata/ # commit and branch records
|
|
refs/ # HEAD references
|
|
replaced/ # recoverable previous checkouts
|
|
```
|
|
|
|
## Development
|
|
|
|
```bash
|
|
cargo fmt --all --check
|
|
cargo test --workspace
|
|
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
|
```
|
|
|
|
Some NPU parser tests use the local, gitignored
|
|
`npu_features/snapshot_20260801` capture. Those tests validate host-side parsing
|
|
only. They are not hardware tests, and a clean clone may not contain the
|
|
fixture.
|
|
|
|
Project-owned low-level Linux calls use `rustix`; AgentOS does not directly add
|
|
`libc` syscall wrappers. This is not a claim that the final `std`/OpenSSL binary
|
|
has no libc ABI dependency.
|
|
|
|
## Known gaps
|
|
|
|
- No long-running AgentOS control daemon or privilege broker yet; the local
|
|
llama-server model transport already uses UDS.
|
|
- No mutation tools or complete privilege-approval path.
|
|
- No streaming remote inference.
|
|
- No completed pure-Rust NPU job submission or physical-board validation.
|
|
- The copy worldline backend lacks Btrfs's kernel-enforced read-only commits.
|
|
- Memory/recall primitives exist as a library but are not exposed as agent tools
|
|
or CLI commands yet.
|
|
|
|
## License notes
|
|
|
|
AgentOS crates declare Apache-2.0. The captured CALCULET PCIe ABI and device
|
|
wrapper crates declare GPL-2.0-only, while `calculet-calrt` retains its vendor
|
|
license file. Check the individual crate manifests before redistribution.
|