# OSagent Documentation Local-first AI agent for your operating system. Made by Locai Labs. Source: https://docs.osagent.computer/ · Repository: https://github.com/LocaiLabs/OSAgent --- # CLI Reference Source: https://docs.osagent.computer/guide/cli-reference # CLI Reference `osagent` ships as a single binary. Run it with no arguments for an interactive REPL, or pass flags to change model, provider, or workspace behaviour. ## Flags ``` osagent Launch interactive chat osagent --model Use a specific GGUF model file osagent --model-url Connect to an existing OpenAI-compatible endpoint osagent --port Force port for the bundled llama-server osagent --no-sandbox Disable OS-level sandboxing for this run osagent --no-thinking Disable chain-of-thought reasoning osagent --reset Archive the current session and start fresh osagent --verbose Show reasoning, timing, and tool detail osagent --debug Show latency breakdown per turn osagent --config Open the configuration wizard (pre-filled from ~/.osagent/config.json) osagent --skip-config Skip the first-run wizard osagent --update Update to the latest released version osagent --uninstall Remove OSagent from your system ``` ## REPL commands | Command | Description | |---|---| | `exit` | Quit the agent | | `reset` | Archive the conversation and start fresh | | `/help` | Show all built-in commands | | `/skills [query]` | List available skills (with optional BM25 search) | | `/skill [request]` | Invoke a skill with an optional user request | | `/ [request]` | Shorthand for `/skill ` | | `/tools` | List the tools the agent currently has | | `/sandbox [on\|off]` | Show or change the sandbox state mid-session | | `/search ` | Switch web-search provider (`linkup`, `tavily`, `none`) | | `/thinking` | Toggle chain-of-thought reasoning | | `/context` | Show token usage, memory & context stats | | `/model` | Show or change the active model (also lists saved provider presets) | | `Ctrl-C` | Abort the current turn | | `Ctrl-C` ×2 | Exit immediately | ::: info Removed pre-launch `/profiles`, `/api-key`, `/edit`, `/models`, `/skills reload`, and `/skills delete` were removed in v0.0.1. Manage providers and rotate keys via `osagent --config`; remove a skill with `rm -rf ~/.osagent/skills/`; use Shift+Enter for multi-line prompts in the composer. ::: ::: tip Multi-line input End a line with `\` to continue on the next line. ::: ## Slash commands and skills Skills are addressable two ways: ```bash /skill code-review src/app.ts # explicit /code-review src/app.ts # shorthand (hyphen and underscore are interchangeable) ``` Built-in commands always win against same-named skills, so a skill called `help` cannot hijack `/help`. ## Configuration wizard `osagent --config` opens an interactive wizard that: 1. Detects your hardware (CPU, RAM, free disk, GPU acceleration). 2. Lists supported local models with size and recommended-RAM hints, **or** lets you connect to a cloud provider (Locai, OpenAI, Anthropic, OpenRouter, custom URL). 3. Downloads the model and vision projector if you picked a local one. 4. Sets the web-search provider (Linkup, Tavily, or none — web search is off until you pick one). 5. Writes everything to `~/.osagent/config.json`. You can re-run it at any time. On a normal install, fields are pre-filled from your existing config so you revise rather than start from scratch. ## See also - [Configuration](/guide/configuration) — every setting that ends up in `config.json` - [Providers](/guide/providers) — local vs cloud, and how to switch - [Troubleshooting](/guide/troubleshooting) — common first-run issues --- # Community Source: https://docs.osagent.computer/guide/community # Community Three places to talk to us and to other people building with OSagent. ## GitHub Discussions The right place for **questions, ideas, "is this a bug?" before it's a bug, and longer threads** that don't belong in an issue. → ## Discord The right place for **real-time chat, sharing what you're building, quick help, and dev coordination**. → ## GitHub Issues The right place for **confirmed bugs and concrete feature requests**. Include: - Your OS and OSagent version (`osagent --debug` prints both). - The model and provider you were using. - Steps to reproduce. → ## Security If you discover a vulnerability, please **do not** post the details in a public issue, GitHub Discussion, or Discord channel. Disclose responsibly so we can ship a fix before details become public. ::: info Pre-1.0 reporting flow OSagent is in pre-1.0 development and the source repository is currently private. While that's the case, the practical reporting channels are: - **DM a maintainer** on [Discord](https://discord.com/invite/vWqFWzRQZq) asking to be put in touch with the security contact. - **DM a Locai Labs maintainer** on GitHub if you already have access to the private repository. When the repo is made public, this page will be updated with a GitHub Private Vulnerability Reporting link and a published security contact address. ::: We commit to: - Acknowledge receipt within **48 hours** - Aim to provide a fix or mitigation within **7 days** for critical issues - Credit reporters publicly once a fix has shipped (with permission) Good-faith security research is welcome. We will not pursue legal action against researchers who follow this policy, give us reasonable time to remediate, and avoid privacy violations or disruptions to other users. ## Code of Conduct All community spaces follow the [Code of Conduct](https://github.com/LocaiLabs/OSAgent/blob/dev/CODE_OF_CONDUCT.md). To report unacceptable behaviour: while OSagent is in pre-1.0 and the team is small, please **DM a Locai Labs maintainer** on [Discord](https://discord.com/invite/vWqFWzRQZq) or GitHub. A dedicated reporting address will be published with the public release. Reports are handled confidentially. --- # Configuration Source: https://docs.osagent.computer/guide/configuration # Configuration All configuration lives in `~/.osagent/config.json`. The first-run wizard creates it; `osagent --config` re-opens it pre-filled. You can also edit the file directly. ::: info Schema is evolving The full schema is defined in [`packages/agent-gateway/src/config.ts`](https://github.com/LocaiLabs/OSAgent/blob/dev/packages/agent-gateway/src/config.ts) (see `OSagentConfig` and `DEFAULT_OSAGENT_CONFIG`). Treat the source as the canonical reference — the keys below are the ones you'll actually touch in v0.1, but more may exist or change. ::: ## Common settings ```json { "model": { "name": "local-model", "url": "http://127.0.0.1:18781/v1", "apiKey": "local-llama" }, "search": { "provider": "none" }, "agent": { "contextWindowSize": 65536, "thinking": true }, "sandbox": { "enabled": true, "allowNetwork": false }, "traces": { "enabled": true } } ``` | Key | Default | Notes | |---|---|---| | `model.name` | `local-model` | Model identifier sent to the endpoint. | | `model.url` | `http://127.0.0.1:18781/v1` | OpenAI-compatible endpoint. | | `model.apiKey` | `local-llama` | Sent as the bearer token. Replace for hosted providers. | | `search.provider` | `none` | `linkup`, `tavily`, or `none`. Web search is off until you pick `linkup` or `tavily` and supply a key. | | `agent.contextWindowSize` | `65536` | Tokens of context window the model supports. | | `agent.thinking` | `true` | Default chain-of-thought toggle. | | `agent.maxToolCalls` | (framework default) | Optional cap on tool calls per turn. | | `sandbox.enabled` | `true` | OS-level sandboxing. | | `sandbox.allowNetwork` | `false` | Allow outbound network from sandboxed `bash`. | | `sandbox.writablePaths` | `[]` | Extra paths the agent may write to. | | `traces.enabled` | `true` | Append per-turn JSONL traces to `~/.osagent/.traces/`. | There are more keys (memory profiles, model profiles, skills disable list, etc.). The wizard surfaces the ones most people need; the source is the rest. ## Web search | Provider | API key env var | Notes | |---|---|---| | `none` | — | Default. `web_search` is dropped from the tool list; `web_fetch` still works for known URLs. | | `linkup` | `LINKUP_API_KEY` | Best quality. Get a key at [linkup.so](https://linkup.so). | | `tavily` | `TAVILY_API_KEY` | LLM-tuned search results. Get a key at [tavily.com](https://tavily.com). | ## Re-running the wizard ```bash osagent --config ``` The wizard reads `~/.osagent/config.json` and pre-fills every field, so you revise rather than start fresh. ## Environment variables | Variable | Purpose | |---|---| | `SEARCH_PROVIDER` | Override `search.provider` for this process | | `LINKUP_API_KEY` | Required for Linkup search | | `TAVILY_API_KEY` | Required for Tavily search | ## See also - [Providers](/guide/providers) - [Sandbox & Safety](/guide/sandbox-and-safety) - [CLI Reference](/guide/cli-reference) --- # Windows & Linux Desktop Source: https://docs.osagent.computer/guide/desktop-tauri # Windows & Linux Desktop ::: warning PLANNED The Tauri desktop app for Windows and Linux is planned for v0.2.0. Contributions are welcome! ::: The Windows and Linux desktop experience will be built with [Tauri](https://tauri.app/), providing a native-feeling application on both platforms. ## Current Status The `apps/desktop-tauri/` directory is a placeholder. The CLI is the recommended way to use OSagent on Windows and Linux today. ## Contributing If you'd like to help build the Tauri desktop app, check the [Contributing guide](/contributing) and the open issues on GitHub labelled `desktop-tauri`. --- # Getting Started Source: https://docs.osagent.computer/guide/getting-started # Getting Started ## Install ### macOS / Linux ```bash curl -fsSL https://cli.osagent.computer/install.sh | sh ``` ### Windows (PowerShell) ```powershell irm https://cli.osagent.computer/install.ps1 | iex ``` The installer downloads the CLI, installs `llama-server` if missing, adds everything to your PATH, and launches the setup wizard. ### macOS Desktop App ::: info Coming soon A native SwiftUI app with floating overlay, system tray, and global hotkey is in development. The CLI is fully functional today; the desktop app will land alongside the v0.2 release. See the [macOS App page](./macos-app) for build-from-source instructions in the meantime. ::: ## First Run ```bash osagent ``` On first run, OSagent checks your hardware, lets you pick a model, and downloads it. Then you're in an interactive chat with full tool access. ``` ___ ____ _ _ / _ \/ ___| / \ __ _ ___ _ __ | |_ | | | \___ \ / _ \ / _` |/ _ \ '_ \| __| | |_| |___) / ___ \ (_| | __/ | | | |_ \___/|____/_/ \_\__, |\___|_| |_|\__| |___/ Model gemma-4-E4B-it-Q4_K_M Search none Thinking on Sandbox off Skills 1 (/skills to list) Tools bash · read · write · edit · search · fetch ❯ list all python files in this directory ┃ ⚡ bash Found 3 Python files: - main.py (142 lines) - utils.py (38 lines) - tests/test_main.py (67 lines) ``` ## Bring Your Own Model Drop any `.gguf` file into `~/.osagent/.models/` and run: ```bash osagent --model my-custom-model-Q5_K_M.gguf ``` ## Data Directory OSagent stores all data in `~/.osagent/`: ``` ~/.osagent/ memory/ User profile and long-term notes (USER.md, MEMORY.md) sessions/ Conversation history (auto-managed) skills/ Reusable procedures (agent-managed) config.json Configuration (created via `osagent --config`) settings.json CLI settings ``` Infrastructure files (models, traces, lock files) are dot-prefixed and hidden from the agent. ## Next Steps - [CLI Reference](/guide/cli-reference) — all flags and REPL commands - [Tools](/guide/tools) — what the agent can do - [Configuration](/guide/configuration) — customise model, search, context window, and more --- # macOS Desktop App Source: https://docs.osagent.computer/guide/macos-app # macOS Desktop App A native SwiftUI app with a floating overlay panel, system tray icon, and global hotkey. ::: warning Coming soon The packaged DMG is not yet available for download. The desktop app is in active development and will ship alongside the v0.2 release. Today you can either use the [CLI](./cli-reference) (fully supported), or build the desktop app from source using the steps below. ::: ## Build from Source If you want to try the desktop app today, build it from source. ### Prerequisites - macOS 15.0+ - Xcode 16+ (with Swift 6.0) - [XcodeGen](https://github.com/yonaskolb/XcodeGen) — `brew install xcodegen` - Node.js >= 18 - `llama-server` on your PATH — `brew install llama.cpp` ## Build and Run ```bash cd apps/desktop-macos # Install deps, build the framework + gateway, generate Xcode project make setup # Build and launch the app make run ``` The app starts its own `llama-server` and Agent Gateway as child processes — no separate terminal needed. It connects to the gateway over WebSocket at `ws://127.0.0.1:18780/ws`. Run `make help` to see all available targets (bundle, dist, clean, etc.). ## Architecture The desktop app runs three processes: 1. **llama-server** — the local inference engine, managed as a child process 2. **Agent Gateway** — Node.js WebSocket server bridging the UI to the agent framework 3. **SwiftUI app** — the native interface connecting to the gateway over WebSocket --- # Memory Source: https://docs.osagent.computer/guide/memory # Memory OSagent stores persistent memory in `~/.osagent/memory/` as plain markdown files that you can read and edit with any text editor. ## Memory Files | File | Purpose | |------|---------| | `USER.md` | User profile — name, preferences, tools, environment | | `MEMORY.md` | Long-term notes — projects, decisions, key facts | ## How It Works The agent reads and updates these files directly with `read_file` and `edit_file`. Memory is loaded into the system prompt at the start of each session, giving the agent context about you and your previous work. - **User profile** builds up over time as the agent learns your name, preferred tools, coding style, and environment - **Long-term notes** capture project-specific decisions, important facts, and anything the agent determines is worth remembering ## Editing Memory Since memory is stored as plain markdown, you can: - Edit files directly in any text editor - Remove information you don't want the agent to remember - Pre-populate the files with context before starting a session - Back up or sync the files across machines ## Session History Separate from memory, conversation history is stored in `~/.osagent/sessions/`. Sessions persist across restarts, so the agent can resume where it left off. Use `osagent --reset` or the `reset` REPL command to archive the current session and start fresh. --- # Providers Source: https://docs.osagent.computer/guide/providers # Providers OSagent talks to anything that exposes the OpenAI Chat Completions wire format at `/v1/chat/completions`. Local `llama-server` is the default; you can point it at a hosted provider or a self-hosted server instead. ## Local (default) The bundled `llama-server` runs a GGUF model on your machine. No accounts, no API keys, no data leaves your computer. ```bash osagent --config # pick a model in the wizard osagent --model my.gguf # bring your own GGUF ``` The setup wizard offers a small curated catalogue and gates recommendations by your detected RAM. The catalogue lives in [`apps/cli/src/model-download.ts`](https://github.com/LocaiLabs/OSAgent/blob/dev/apps/cli/src/model-download.ts); expect it to evolve as new models land. ## Hosted The setup wizard offers four hosted presets and a "Custom URL" option for anything else: | Preset | Base URL | Notes | |---|---|---| | Locai | `https://api.locailabs.com/v1` | Locai-hosted open models. | | OpenAI | `https://api.openai.com/v1` | OpenAI's standard endpoint. | | Anthropic | `https://api.anthropic.com/v1` | Claude via Anthropic's [OpenAI-compatible endpoint](https://platform.claude.com/docs/en/api/openai-sdk). | | OpenRouter | `https://openrouter.ai/api/v1` | OpenRouter's standard endpoint. | | Custom URL | (anything) | Self-hosted vLLM, Ollama, SGLang, LM Studio, etc. | The presets just set `model.url` and `model.apiKey` for you. You can write the same thing in `~/.osagent/config.json`: ```json { "model": { "name": "your-model-id", "url": "https://api.example.com/v1", "apiKey": "..." } } ``` ::: info Compatibility "Compatible" means the provider speaks the OpenAI wire format closely enough for our agent loop. Tool-calling, streaming, and reasoning tags vary in practice. If a provider you'd like to use doesn't quite work, open an issue with the symptom — quirks are usually small fixes in [`OpenAICompatibleModelClient`](https://github.com/LocaiLabs/OSAgent/blob/dev/packages/agent-framework-ts/src/model/openai_compatible_client.ts). ::: ## Switching at runtime ```bash osagent --model-url http://localhost:11434/v1 # e.g. local Ollama osagent --model-url https://api.openai.com/v1 ``` In the REPL: - `/model` — show or change the active model. The picker also lists every saved provider preset, so a single command covers what `/profiles` used to. To add or rename presets, or to rotate an API key, run `osagent --config`. ## Vision `read_file` can attach JPEG/PNG/GIF pixels to the prompt when the model supports vision. For local models, the matching `mmproj` projector must be present alongside the GGUF (the wizard downloads it for the bundled multimodal models). Hosted models that support vision should work, but mileage varies — open an issue if you hit something odd. ## Thinking / reasoning Some models can be told to reason before answering. Toggle per-session with `/thinking`, or in the config: ```json { "agent": { "thinking": true } } ``` OSagent sends `enable_thinking: true` to providers that honour it and strips `` tags from the visible response so they show up in the collapsible reasoning UI rather than the message body. ## See also - [Configuration](/guide/configuration) - [CLI Reference](/guide/cli-reference) - [Sandbox & Safety](/guide/sandbox-and-safety) --- # Roadmap Source: https://docs.osagent.computer/guide/roadmap # Roadmap Where OSagent is heading. Dates are deliberately absent — this is a small team and the order matters more than the calendar. Contributions on any of these are welcome; open an issue or jump in on [Discussions](https://github.com/LocaiLabs/OSAgent/discussions) / [Discord](https://discord.com/invite/vWqFWzRQZq) before starting something large so we can sync. ## Shipping next - **Cross-platform desktop apps.** A native macOS app is in active development. Windows and Linux desktop apps will follow via Tauri — the placeholder lives at `apps/desktop-tauri/`. Contributions especially welcome here. - **Plugin system for tools.** Today user tools live in `~/.osagent/.tools/` and are loaded at startup ([User Tools](/framework/user-tools)). The next iteration extends this into a fuller plugin system — richer manifest, lifecycle hooks, packaging, discoverability — so the agent's capability surface can grow without forking the framework. - **Dispatch & connectivity channels.** Today OSagent runs interactively in the CLI or desktop app. Next we want the agent to be reachable through other channels — webhooks, scheduled triggers, messaging surfaces — so it can act on events as well as prompts. - **Better self-learning.** The agent already creates skills after complex tasks. We want to make that loop measurably better: skills the agent actually re-uses, retired skills it knows to delete, and honest evaluation of whether new skills helped. ## Longer term - A public eval harness so changes to the agent loop, prompts, or models can be measured rather than vibes-checked. - A small library of design notes covering the non-obvious choices in the framework (the cache-stable system prompt, the tool-result envelope, the per-file memory caps). - Better observability — first-class metrics from the existing event emitter, and a way to replay a session deterministically from its trace. ## How to help - **Try it on your hardware** and open issues for what doesn't work. Bug reports with `osagent --debug` output are gold. - **Pick anything from "Shipping next"** and open a PR. If it's non-trivial, sketch the approach in an issue first. - **Write a skill** that the agent should know about and contribute it back via `packages/agent-gateway/skills/`. - **Port a tool** you wish you had — the [User Tools](/framework/user-tools) page is the easiest way to start. See [CONTRIBUTING.md](https://github.com/LocaiLabs/OSAgent/blob/dev/CONTRIBUTING.md) for the developer setup. --- # Sandbox & Safety Source: https://docs.osagent.computer/guide/sandbox-and-safety # Sandbox & Safety OSagent gives the model real tools — file I/O and shell execution — so a couple of layers try to keep things sensible: 1. **A safety hook** rejects obviously destructive `bash` commands before they run. 2. **An optional OS sandbox** (Seatbelt on macOS, bubblewrap on Linux) limits what `bash` can reach. Neither is bulletproof. Treat OSagent like any other tool with shell access — don't run it as root, don't point it at directories you can't afford to lose, and check what it does. ## Safety hook `bashSafetyHook` is always on. It rejects `bash` commands that match known-dangerous patterns (`rm -rf /`, `mkfs.*`, `dd if=…`, raw block device writes, recursive `chmod 777 /`, fork bombs) and interactive commands that would hang the headless shell (`vim`, `less`, `ssh`, bare `python` / `node` REPLs, etc.). Package installs (`npm install`, `pip install`, `brew install`, `cargo add`, …) prompt for confirmation in the CLI. The desktop app shows a similar prompt. The exact pattern list lives in [`hooks.ts`](https://github.com/LocaiLabs/OSAgent/blob/dev/packages/agent-framework-ts/src/hooks.ts) — check the source if you need certainty. ## OS sandbox When `sandbox.enabled` is `true`, `bash` runs through `sandbox-exec` (macOS) or `bwrap` (Linux). The default policy: | | Default | |---|---| | Read filesystem | allowed | | Write to **CWD**, `~/.osagent`, `/tmp` | allowed | | Write elsewhere | denied | | Read `~/.ssh`, `~/.aws`, `~/.gnupg`, `~/.config/gcloud` | denied | | Outbound network | denied | Add extra writable paths or allow network in `~/.osagent/config.json`: ```json { "sandbox": { "enabled": true, "writablePaths": ["/Users/me/projects"], "allowNetwork": true } } ``` Bypass for one session: ```bash osagent --no-sandbox ``` In the REPL: `/sandbox off` / `/sandbox on`. ## Honest limits - The sandbox only wraps `bash`. Other tools (`web_fetch`, `web_search`, the model's own provider connection) are not sandboxed. - It will not protect you from a model that writes malicious code into your project files — the agent will write whatever you ask it to. - It is a best-effort layer, not a security boundary against an attacker. For higher-assurance use, run inside a VM or container. ## Custom hooks You can add your own pre/post-tool hooks. See [Hooks](/framework/hooks). ## See also - [Hooks](/framework/hooks) - [CLI Reference](/guide/cli-reference) - [Configuration](/guide/configuration) --- # Skills Source: https://docs.osagent.computer/guide/skills # Skills Skills are reusable procedures the agent creates, updates, and follows. They live in `~/.osagent/skills/` as markdown files. ## How Skills Work - The agent sees a lightweight index of skill names and descriptions each turn - When a skill is relevant, the agent loads it via `read_file` (just-in-time, no wasted tokens) - After complex tasks (5+ tool calls or error recovery), the agent creates new skills autonomously - You can also create skills manually or ask the agent to create one ## Bundled Skills **`system-info`** — reports macOS hardware and resource status. OSagent ships with bundled skills in `packages/agent-gateway/skills/`. These are automatically copied to `~/.osagent/skills/` on first run. ## Creating Custom Skills Skills are simply markdown files with YAML frontmatter. Create a file in `~/.osagent/skills/your-skill/SKILL.md`: ```markdown --- name: your-skill description: A brief description of what this skill does tags: [relevant, tags] --- # Your Skill Step-by-step instructions the agent will follow... ``` The agent indexes the `name` and `description` fields and loads the full content only when the skill is relevant to the current task. ## Using Skills In the REPL, you can explicitly invoke a skill: ``` /skills # List available skills /skill system-info # Run with a specific skill ``` Or simply describe your task — the agent will automatically detect and load relevant skills from the index. --- # Tools Source: https://docs.osagent.computer/guide/tools # Tools OSagent comes with a set of built-in tools that give the agent real capabilities on your machine. ## Built-in Tools ### bash Runs shell commands on your machine. Protected by the `bashSafetyHook` which blocks known dangerous patterns (`rm -rf /`, `mkfs`, fork bombs, etc.). ### read_file Reads the contents of any file accessible to your user account. Supports text files, and with optional tools, PDFs and images. ### write_file Creates or overwrites files. The agent uses this for generating code, configuration files, notes, and more. ### edit_file Makes targeted edits to existing files — find-and-replace with context. Safer than rewriting entire files for small changes. ### web_search Searches the web via Linkup or Tavily (bring your own API key). Web search is off by default; enable it from the wizard, the desktop Settings → Tools tab, or with `/search linkup|tavily` in the CLI. ### web_fetch Fetches the full content of a web page when search snippets don't provide enough detail. ## Safety All tool execution passes through the hooks system. The default `bashSafetyHook` blocks destructive shell patterns before they execute. You can add custom pre- and post-tool hooks to enforce your own policies. The `--no-sandbox` flag disables OS-level sandboxing but the hook-based safety checks remain active regardless. ## Optional Tools The framework also provides standalone tools that can be enabled: | Tool | Description | |------|-------------| | `read_image` | Analyses images using a vision-capable model | | `read_document` | Reads PDFs, DOCX, XLSX, and CSV files | | `save_memory` | Explicitly saves information to persistent memory | See the [Framework Tools](/framework/tools) documentation for details on using these programmatically. --- # Troubleshooting Source: https://docs.osagent.computer/guide/troubleshooting # Troubleshooting A short list of things people hit early. If you run into something not listed here, please [open an issue](https://github.com/LocaiLabs/OSAgent/issues) with the output of `osagent --debug` — that's how this page grows. ## `command not found: osagent` after install Open a new terminal (the installer adds `~/.local/bin` to your shell profile, but the current shell doesn't see it yet). If `~/.local/bin` isn't on your PATH at all: ```bash echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc ``` ## `llama-server` not found The local-model path needs `llama-server` from `llama.cpp`: ```bash brew install llama.cpp # macOS ``` On Linux, build from source or grab a release binary from [ggml-org/llama.cpp](https://github.com/ggml-org/llama.cpp). If you're only using a hosted provider, you can ignore this — set `model.url` to the provider endpoint and OSagent will skip the local server. ## Model is too big for my RAM The wizard flags oversized models with `⚠`. If you already downloaded one that won't load, swap to a smaller one: ```bash osagent --config # pick a smaller model ``` Files in `~/.osagent/.models/` are safe to delete to free space. ## Port already in use `llama-server` defaults to 18781, the gateway to 18780. If something else is already on those ports: ```bash osagent --port 18790 ``` To find what's holding a port: `lsof -iTCP:18781 -sTCP:LISTEN`. ## Outbound network not working from `bash` The sandbox blocks outbound network by default. Either allow it in config (`sandbox.allowNetwork: true`), disable the sandbox for this run (`--no-sandbox`), or use a tool that runs outside the sandbox (`web_fetch`, `web_search`). ## The agent forgot something I told it Long sessions get **compacted** — older turns are summarised. Important facts should land in long-term memory: > "Remember that I prefer Vue 3 composition API." The agent will write this to `MEMORY.md`. You can also edit `~/.osagent/memory/MEMORY.md` directly. ## I want to start over ```bash osagent --reset ``` Or in the REPL: `reset`. ## Update fails Re-run the installer — it overwrites in place: ```bash curl -fsSL https://cli.osagent.computer/install.sh | sh ``` ## Something else [Open an issue](https://github.com/LocaiLabs/OSAgent/issues) — even short reports help. Include OS, model, and the relevant snippet from `osagent --debug` when you can. --- # What is OSagent? Source: https://docs.osagent.computer/guide/what-is-osagent # What is OSagent? OSagent is a local-first AI agent for your operating system, made by Locai Labs. It runs entirely on your machine by default — no cloud services, no API keys, no data leaves your computer — and you can plug in a hosted model when you want to. It downloads and runs open-weight GGUF models via `llama.cpp`, gives the model tools to read/write files, execute shell commands, and search the web, and remembers context across sessions in plain markdown files you can read and edit. ## Key Features - **Read, create, and edit files** via `read_file`, `write_file`, `edit_file` - **Run shell commands** via `bash` (with safety hooks that block dangerous patterns) - **Search the web** (optional) via Linkup or Tavily — bring your own API key - **Fetch web pages** via `web_fetch` when search results lack detail - **Remember** across sessions — user profile and long-term notes stored as plain markdown - **Resume conversations** automatically — sessions persist across restarts - **Learn from experience** — creates reusable skills after complex tasks - **Use custom skills** — extensible skill system with just-in-time loading ## Architecture OSagent is a monorepo with several packages: ``` apps/ cli/ # Bun-compiled CLI binary desktop-macos/ # Native Swift macOS app desktop-tauri/ # Windows + Linux (planned) packages/ agent-framework-ts/ # Core TypeScript agent library agent-gateway/ # Session management, prompt pipeline, WebSocket bridge scripts/ # Signing, notarising, DMG creation, bootstrap ``` ### Agent Framework The core TypeScript library that powers the agent. It handles streaming, tool execution, context management, and multi-turn conversation. Works with any OpenAI-compatible LLM endpoint. ### Agent Gateway A Node.js server that bridges native GUI apps to the agent framework over WebSocket. Manages sessions, the prompt pipeline, memory loading, and skill indexing. ### CLI A cross-platform command-line interface compiled with Bun. Provides an interactive REPL with tool access, model management, and configuration. ### Desktop Apps Native desktop applications that connect to the Agent Gateway for a richer user experience. The macOS app is a SwiftUI application with a floating overlay panel, system tray icon, and global hotkey. ## Design Principles 1. **Local first** — everything runs on your hardware; no cloud dependency 2. **Transparent** — memory files are plain markdown; configuration is JSON; skills are readable documents 3. **Safe by default** — shell commands are screened by safety hooks; network binds to localhost only 4. **Extensible** — custom tools, hooks, skills, and model clients can be plugged in --- # Agent Source: https://docs.osagent.computer/framework/agent # Agent The `Agent` class is the main entry point for the framework. It handles streaming, tool execution, context management, and multi-turn conversation. ## Constructor ```ts const agent = new Agent({ systemPrompt: "...", modelName: "gpt-4o", modelUrl: "http://127.0.0.1:8080/v1", tools: [], maxTotalToolCalls: 10, maxParallelToolCalls: 1, contextWindowSize: 65536, streamingHandler: (event) => { ... }, hooksConfig: { ... }, }); ``` ### Options | Option | Type | Description | |--------|------|-------------| | `systemPrompt` | `string` | System message prepended to every request | | `modelName` | `string` | Model identifier sent to the endpoint | | `modelUrl` | `string` | OpenAI-compatible API base URL | | `modelApiKey` | `string` | API key (if required by the endpoint) | | `modelClient` | `ModelClient` | Custom model client (overrides URL/key) | | `tools` | `Tool[]` | Array of tools available to the agent | | `dependencies` | `T` | Typed dependencies injected into tool functions | | `maxTotalToolCalls` | `number` | Maximum tool calls per turn | | `maxParallelToolCalls` | `number` | Maximum concurrent tool executions | | `contextWindowSize` | `number` | Context window size in tokens | | `streamingHandler` | `function` | Callback for streaming events | | `hooksConfig` | `object` | Pre- and post-tool hooks configuration | | `skillsPrompt` | `string` | Skills index injected into the system prompt | ## Running the Agent ```ts const { response, history } = await agent.run("Hello", previousHistory); ``` The `run` method takes a user message and optional conversation history, and returns the agent's response along with the updated history. ## Multi-turn Conversations Pass `history` between turns to maintain context: ```ts let history = []; const turn1 = await agent.run("My name is Alice.", history); history = turn1.history; const turn2 = await agent.run("What is my name?", history); // → "Your name is Alice." ``` ## Typed Dependencies The `Agent` class supports generic type parameters for dependency injection into tools: ```ts interface MyDeps { userId: string; db: Database; } const agent = new Agent({ dependencies: { userId: "user_123", db: myDatabase }, tools: [myToolThatUsesDeps], // ... }); ``` --- # Architecture Source: https://docs.osagent.computer/framework/architecture # Architecture A quick sketch of how the pieces fit together. Internals will change between releases — read the source if you depend on details. ## System overview ```mermaid flowchart LR CLI["CLI
Bun binary"] Desktop["Desktop App
Swift / macOS"] subgraph Shared["Shared packages"] Gateway["agent-gateway"] Framework["agent-framework-ts"] end Llama["llama-server
(local)"] Cloud["Hosted provider
(OpenAI-compatible)"] CLI -->|direct import| Gateway Desktop -->|WebSocket| Gateway Gateway --> Framework Framework -->|/v1/chat/completions| Llama Framework -.->|/v1/chat/completions| Cloud ``` Both frontends drive the same `Agent` instance. The CLI imports the gateway directly; the desktop app talks to a Node-hosted gateway over a local WebSocket. The framework speaks the OpenAI Chat Completions wire format, so any compatible endpoint can sit on the right. ## A turn, roughly ```mermaid sequenceDiagram actor User participant Bridge as AgentBridge participant Agent participant Model as ModelClient participant Exec as ToolExecutor User->>Bridge: sendMessage(text) Bridge->>Agent: run(userContent, history) loop until no tool calls Agent->>Model: streamChat(messages, tools) Model-->>Agent: text + toolCalls[] alt toolCalls present Agent->>Exec: execute(toolCalls) Exec->>Exec: preToolHooks → tool.fn() → postToolHooks Exec-->>Agent: results[] end end Agent-->>Bridge: {response, history} Bridge-->>User: response ``` The model decides when to stop calling tools by emitting a final assistant message with no tool calls. The agent enforces an upper bound (`maxTotalToolCalls`) so a runaway model can't loop forever. ## Memory and skills - **Memory** — `~/.osagent/memory/USER.md` and `MEMORY.md`. The agent reads/modifies them through the `memory` tool. - **Skills** — `~/.osagent/skills//SKILL.md`. The agent sees a lightweight name+description index every turn and loads the body with `read_file` only when relevant. - **Sessions** — `~/.osagent/sessions//`. See [Memory](/guide/memory), [Skills](/guide/skills), and [Context & Compaction](/framework/context-and-compaction) for the rest. ## Sandboxing `bash` runs inside an OS sandbox by default — Seatbelt on macOS, bubblewrap on Linux. Hook-level safety checks remain active even when the sandbox is off. See [Sandbox & Safety](/guide/sandbox-and-safety). ## Observability Three surfaces, listed in [Streaming](/framework/streaming), [Events](/framework/events), and [Traces](/framework/traces). Pick whichever fits your use case — they're additive, not exclusive. --- # Context & Compaction Source: https://docs.osagent.computer/framework/context-and-compaction # Context & Compaction Long sessions overflow the model's context window. The agent summarises older turns before that happens and emits warnings on the way. ## How it works Before each model call, a `ContextManager`: 1. Counts tokens. 2. Emits `context:warning` and `context:critical` streaming events when usage crosses configurable thresholds. 3. **Compacts** the history when it would otherwise exceed the window — summarises older turns into a single condensed message and drops the originals. The most recent turns stay verbatim. If summarisation fails, the manager falls back to dropping the middle turns with a placeholder marker rather than letting the window grow unbounded. ## Tool-pair safety The compactor never separates an assistant `tool_calls` message from the matching `tool` results — that would leave unmatched IDs and trip the provider. ## Memory survives compaction Compaction only affects in-session history. Long-term memory (`USER.md`, `MEMORY.md`) lives outside the conversation; the agent re-reads it via the `memory` tool when relevant. Encourage the agent to save anything important — it survives compaction *and* restarts. ## Tuning ```json { "agent": { "contextWindowSize": 131072 } } ``` Bigger window = fewer compactions, slower turns, more memory. The default 65 536 is a good fit for the bundled quantised local models. ## Helpers `HistoryWindow`, `SessionEvictor`, `MemoryGuard` are exported for embedders that want manual control. The bundled gateway uses `HistoryWindow` to flush completed turns to disk so it doesn't hold the full transcript in memory. ## Streaming events | Event | When | |---|---| | `context:update` | Every turn — periodic usage update for status bars | | `context:warning` | First time usage crosses the warning threshold | | `context:critical` | First time usage crosses the critical threshold | ## See also - [Streaming](/framework/streaming) - [Memory](/guide/memory) - [Events](/framework/events) --- # Events Source: https://docs.osagent.computer/framework/events # Events `AgentEventEmitter` is a typed event bus for observability — session start, turn boundaries, model calls, compaction. Read-only: events cannot block or modify behaviour. For that, use [Hooks](/framework/hooks). ## Subscribing ```ts import { Agent, AgentEventEmitter } from "@locailabs/agent-framework"; const events = new AgentEventEmitter(); events.on("turn:end", (e) => console.log(`turn ${e.turn}: ${e.latencyMs}ms`)); events.on("compaction", (e) => metrics.increment("compactions")); const agent = new Agent({ events, /* ... */ }); ``` `on()` returns an unsubscribe function. ## Event types The current event map lives in [`packages/agent-framework-ts/src/events.ts`](https://github.com/LocaiLabs/OSAgent/blob/dev/packages/agent-framework-ts/src/events.ts) — short and easy to read. As of v0.1: - `session:start`, `session:end` - `turn:start`, `turn:end` - `pre:model`, `post:model` - `compaction` - `context:warning`, `context:critical` Payloads are typed; check the source for fields. ## When to use what | Surface | Good for | Affects control flow? | |---|---|---| | **Streaming events** (`streamingHandler`) | UI updates, typewriter output | No | | **Hooks** (`hooksConfig`) | Block, modify, confirm individual tool calls | Yes | | **Events** (`AgentEventEmitter`) | Metrics, audit log, external observability | No | Most agents use all three. ## See also - [Streaming](/framework/streaming) - [Hooks](/framework/hooks) - [Context & Compaction](/framework/context-and-compaction) --- # Hooks Source: https://docs.osagent.computer/framework/hooks # Hooks Hooks run custom logic before or after every tool call, and at session and turn boundaries. Use them to block dangerous commands, request user confirmation, log usage, or modify results. ## Hook configuration ```ts import { bashSafetyHook, auditLoggerHook, makePackageConfirmHook, } from "@locailabs/agent-framework"; const agent = new Agent({ hooksConfig: { preToolUse: [bashSafetyHook, makePackageConfirmHook({ rl })], postToolUse: [auditLoggerHook], onSessionStart: [], onSessionEnd: [], onTurnStart: [], onTurnEnd: [], onPreModel: [], onPostModel: [], onCompaction: [], }, }); ``` Pre-tool hooks run in order. The first hook to return `{ allow: false }` short-circuits the rest, the tool is never called, and the model receives the `blockedReason` as the tool result. Lifecycle hooks (`onSession*`, `onTurn*`, `onPreModel`, `onPostModel`, `onCompaction`) are observability hooks — their return value is `{ ok: boolean } | void` and does not affect control flow. ## Built-in hooks ### `bashSafetyHook` Blocks known-dangerous bash patterns (`rm -rf /`, `mkfs.*`, `dd if=…`, writes to raw block devices, recursive `chmod 777 /`, fork bombs) and interactive commands the headless shell cannot drive (`vim`, `less`, `ssh`, bare `python`/`node` REPLs). ### `makePackageConfirmHook({ rl })` Returns a pre-tool hook that intercepts package-manager installs (`npm install`, `pip install`, `brew install`, `cargo add`, `go get`, etc.) and prompts the user via the supplied `readline/promises` interface before allowing them through. Use this in the CLI; the desktop app uses a UI confirmation prompt instead. ### `auditLoggerHook` Post-tool hook that prints `tool_name` and `durationSeconds` to stderr. Useful during development; replace with your own logger for production. ## Custom hooks ### Pre-tool hook ```ts import type { PreToolHook } from "@locailabs/agent-framework"; const myHook: PreToolHook = async (ctx) => { if (ctx.toolName === "bash" && /sudo/.test(String(ctx.arguments.command))) { return { allow: false, blockedReason: "sudo is not allowed in this session" }; } return { allow: true }; }; ``` Optional fields: - `modifiedArguments` — return a modified args object to rewrite the call before it executes (e.g. inject a flag, normalise a path). ### Post-tool hook ```ts import type { PostToolHook } from "@locailabs/agent-framework"; const redactHook: PostToolHook = async (ctx) => { if (ctx.toolName === "bash" && ctx.result?.includes("API_KEY=")) { return { modifiedResult: ctx.result.replace(/API_KEY=\S+/g, "API_KEY=***") }; } return {}; }; ``` The post-tool hook receives `ctx.result`, `ctx.durationSeconds`, and `ctx.error` (if the tool threw). ### Lifecycle hook ```ts import type { LifecycleHook } from "@locailabs/agent-framework"; const onTurnEnd: LifecycleHook = async (ctx) => { console.log(`Turn ${ctx.turn} finished`); }; ``` ## Hook context ```ts interface ToolHookContext { toolName: string; toolCallId: string; arguments: Record; result?: string; // post-tool hooks only durationSeconds?: number; // post-tool hooks only error?: string; // post-tool hooks only (tool threw) } ``` ## See also - [Tool result contract](/framework/tool-result-contract) — what `result` looks like - [Sandbox & Safety](/guide/sandbox-and-safety) — OS-level sandboxing complements hook-level checks --- # Model Client Source: https://docs.osagent.computer/framework/model-client # Model Client The `Agent` supports a pluggable `modelClient` interface. This lets you keep the same tool loop while swapping transport or runtime — for example, an on-device React Native client, a custom proxy, or a different API format. ## Interface ```ts import type { ModelClient } from "@locailabs/agent-framework"; const myModelClient: ModelClient = { async streamChat(request, callbacks) { // Implement provider-specific streaming and call: // callbacks?.onTextDelta(...) // callbacks?.onToolStart(...) return { text: "", toolCalls: [] }; }, async completeChat(request) { return ""; }, }; ``` ## Using a Custom Client ```ts const agent = new Agent({ modelName: "my-model", modelClient: myModelClient, tools: [...makeGeneralTools(), ...makeSearchTools()], }); ``` When a `modelClient` is provided, the `modelUrl` and `modelApiKey` options are ignored — all communication goes through your client implementation. ## Callbacks The `streamChat` method receives callbacks for streaming events: | Callback | Description | |----------|-------------| | `onTextDelta(delta)` | Called with each chunk of text as it streams | | `onToolStart(name, args)` | Called when the model requests a tool call | Your client implementation is responsible for parsing the provider's response format and calling these at the appropriate times. ## Use Cases - **On-device inference** — wrap a local model runtime (e.g. React Native, WASM) - **Custom proxies** — route through an authentication or rate-limiting proxy - **Non-OpenAI APIs** — adapt Anthropic, Google, or other API formats - **Testing** — mock model responses for deterministic test suites --- # Agent Framework Overview Source: https://docs.osagent.computer/framework/overview # Agent Framework Overview The Agent Framework (`@locailabs/agent-framework`) is the core TypeScript library that powers OSagent. It works with most OpenAI-compatible LLM endpoints — llama.cpp, vLLM, Ollama, OpenAI, and others have been used in practice. ::: warning Version 0.1 This is the first public release. The agent loop, tools, and the gateway are functional, but the public API and config keys may change before 1.0. When in doubt, the source under `packages/agent-framework-ts/src/` is the canonical reference. Bug reports and PRs welcome. ::: ## Quick Start ```ts import { Agent, makeGeneralTools, makeSearchTools } from "@locailabs/agent-framework"; const agent = new Agent({ systemPrompt: "You are a helpful assistant.", modelName: "your-model-name", modelUrl: "http://127.0.0.1:8080/v1", modelApiKey: "your-key", tools: [...makeGeneralTools(), ...makeSearchTools()], }); const { response } = await agent.run("What is today's date?"); console.log(response); ``` ## Core concepts | Concept | Description | |---------|-------------| | [Architecture](/framework/architecture) | System overview and the agent turn cycle | | [Agent](/framework/agent) | Main class — streaming, tool execution, context management, multi-turn | | [Tools](/framework/tools) | Pair an async function with an OpenAI-compatible schema | | [Tool Result Contract](/framework/tool-result-contract) | The `{ok, …}` envelope that lets the model recover from tool failures | | [Hooks](/framework/hooks) | Pre/post-tool and lifecycle callbacks — safety, confirmation, logging | | [Skills](/framework/skills) | Markdown-based instruction modules loaded on demand | | [User Tools](/framework/user-tools) | Drop in custom tools at runtime via `~/.osagent/.tools/` | | [Model Client](/framework/model-client) | Pluggable transport interface for custom LLM providers | | [Streaming](/framework/streaming) | Real-time event handler for text deltas, tool calls, context warnings | | [Events](/framework/events) | Out-of-band lifecycle emitter for observability | | [Context & Compaction](/framework/context-and-compaction) | How long sessions stay within the model window | | [Traces](/framework/traces) | Per-turn JSONL records and SFT export | ## Installation Within the OSagent monorepo, packages reference the framework via `file:` dependencies. For standalone use: ```bash npm install @locailabs/agent-framework ``` ## Environment Variables | Variable | Description | Required | |----------|-------------|----------| | `SEARCH_PROVIDER` | Search backend: `linkup` \| `tavily` (unset = `web_search` returns a clear "not configured" error) | Required for `web_search` | | `LINKUP_API_KEY` | Linkup API key | Only if `SEARCH_PROVIDER=linkup` | | `TAVILY_API_KEY` | Tavily API key | Only if `SEARCH_PROVIDER=tavily` | --- # Skills (Framework) Source: https://docs.osagent.computer/framework/skills # Skills (Framework) The framework provides a `SkillLoader` class and `makeReadSkillTool` factory for integrating the skills system into your agent. ## Loading Skills ```ts import { SkillLoader, makeReadSkillTool } from "@locailabs/agent-framework"; const loader = new SkillLoader(["./skills"]); await loader.load(); const agent = new Agent({ tools: [makeReadSkillTool(loader)], skillsPrompt: loader.formatPrompt(), }); ``` ## How It Works 1. **`SkillLoader`** scans the provided directories for `SKILL.md` files with YAML frontmatter 2. **`formatPrompt()`** generates a compact index of skill names and descriptions for the system prompt 3. **`makeReadSkillTool()`** creates a `read_skill` tool that the agent can call to load full skill content on demand This just-in-time loading approach keeps the context window efficient — the agent only loads skill content when it's relevant to the current task. ## Skill Format Skills are markdown files with YAML frontmatter: ```markdown --- name: my-skill description: Brief description for the index tags: [relevant, tags] --- # My Skill Detailed step-by-step instructions... ``` ## Directories The `SkillLoader` accepts an array of directories to scan. OSagent ships with a single user-scoped directory; the multi-dir API is kept so embedders (e.g. binary distributions that bundle their own skills) can layer extra read-only sources without breaking user-installed skills. ```ts const loader = new SkillLoader([ "./bundled-skills", // optional: shipped with the binary "~/.osagent/skills", // user and agent-created skills (canonical home) ]); ``` Project-scoped skills (a `.osagent/skills/` folder in the current working directory) are deliberately not supported — installs are per-user, not per-project. See AGB1-265. --- # Streaming Source: https://docs.osagent.computer/framework/streaming # Streaming The agent emits real-time events via a `streamingHandler` callback. Use it to drive a typewriter UI, surface tool activity, show context-window warnings, or pipe progress over a transport (WebSocket, SSE). ## Streaming handler ```ts const agent = new Agent({ streamingHandler: (event) => { switch (event.type) { case "text_delta": process.stdout.write(event.delta); break; case "tool_start": console.log(`→ ${event.toolName}`); break; case "tool_end": console.log(`✓ ${event.toolName} (${event.durationSeconds.toFixed(2)}s)`); break; case "tool_blocked": console.warn(`✗ ${event.toolName} blocked: ${event.reason}`); break; case "context:warning": case "context:critical": console.warn(`Context at ${event.percent}%`); break; case "done": process.stdout.write("\n"); break; } }, }); ``` ## Event types | Event | Fields | When | |---|---|---| | `text_delta` | `delta: string` | Each chunk of model text as it streams. | | `tool_start` | `toolName`, `toolCallId` | The model has emitted a tool call and the agent is about to execute it. | | `tool_args` | `toolName`, `toolCallId`, `args` | Parsed arguments for the pending tool call. | | `tool_output_delta` | `toolCallId`, `delta` | Streaming output from a long-running tool (currently used by `bash`). | | `tool_end` | `toolName`, `toolCallId`, `result`, `durationSeconds` | The tool has finished. | | `tool_blocked` | `toolName`, `reason` | A pre-tool hook returned `{ allow: false }`. | | `tool_limit_reached` | `used`, `limit`, `resolve(continue)` | The agent hit `maxTotalToolCalls`. Call `resolve(true)` to keep going, `resolve(false)` to stop. | | `usage` | `promptTokens`, `completionTokens`, `totalTokens` | Token counts reported by the provider at end-of-stream. | | `context:warning` | `usedTokens`, `maxTokens`, `percent` | Context window crossed the warning threshold. | | `context:critical` | `usedTokens`, `maxTokens`, `percent` | Context window crossed the critical threshold (compaction imminent). | | `context:update` | `usedTokens`, `maxTokens`, `percent` | Periodic context-usage update for status bars. | | `done` | — | The current `agent.run(...)` call has finished. | ## Patterns - **CLI typewriter** — write `text_delta` deltas straight to stdout. - **Desktop apps** — forward events as JSON frames over a WebSocket so the UI can update without polling. - **Confirmation UX** — handle `tool_limit_reached` by asking the user whether to continue, then call `resolve(continueRunning)`. - **Status bar** — update on `context:update` and `usage` to show live token usage. - **Logging / metrics** — emit timings on `tool_end` and `usage`. ## See also - [Events](/framework/events) — out-of-band lifecycle events for observability - [Hooks](/framework/hooks) — modify or block calls (events are read-only) --- # Tool Result Contract Source: https://docs.osagent.computer/framework/tool-result-contract # Tool Result Contract Built-in tools return strings in a small set of shapes so the model can tell success from failure. The same shapes are recommended (not enforced) for your own tools. ## Two shapes **`bash`** results begin with one of three plain-text headers: | Header | Meaning | |---|---| | `[OK]` | Command exited 0. | | `[FAILED — exit code N]` | Command exited non-zero. | | `[TIMED OUT — Ns]` | Command was killed at the timeout. | **Most other tools** return a JSON envelope: ```jsonc { "ok": true, "data": { /* tool-specific */ } } { "ok": false, "error": "human-readable reason" } ``` Two ergonomic exceptions: - `read_file` returns the file contents directly on success. - `web_fetch` returns the page text directly on success. Both use the JSON envelope on failure. ## Helpers ```ts import { toolOk, toolFail, toolOkWith } from "@locailabs/agent-framework"; return toolOk(); // {"ok":true} return toolFail("path does not exist"); // {"ok":false,"error":"…"} return toolOkWith({ files: ["a.ts", "b.ts"] }); // {"ok":true,"files":["a.ts","b.ts"]} ``` ## Why this matters Smaller models sometimes assume success and read the body of a tool result as if the call worked even when it didn't. The status header gives the model a fixed signal to anchor on, and the bundled system prompt explicitly tells it to acknowledge failures rather than invent outcomes. If you write a custom tool and stick to this shape, you get the same behaviour for free. ## See also - [Tools](/framework/tools) - [Hooks](/framework/hooks) - [Streaming](/framework/streaming) --- # Tools Source: https://docs.osagent.computer/framework/tools # Tools A **tool** is an async function paired with an OpenAI-compatible JSON schema. The model decides when to call a tool from the schema description, the agent runs it, and the stringified result is fed back into the next turn. ## Defining a tool ```ts import { Tool } from "@locailabs/agent-framework"; interface MyDeps { userId: string; } const myTool = new Tool( async (args, deps) => { return `Hello ${deps.userId}, you asked: ${args.question}`; }, { type: "function", function: { name: "my_tool", description: "A custom tool.", parameters: { type: "object", properties: { question: { type: "string", description: "The question." }, }, required: ["question"], }, }, }, ); ``` The function returns a `string`. For structured results, return a JSON string that follows the [tool-result envelope](/framework/tool-result-contract). ## Built-in tools ```ts import { makeGeneralTools, makeFindFilesTool, makeSearchFilesTool, makeReadFileTool, makeMemoryTool, makeSessionSearchTool, makeSearchTools, makeWebSearchTool, makeWebFetchTool, } from "@locailabs/agent-framework"; ``` ### `makeGeneralTools(sandboxConfig?, options?)` Returns the agent's day-to-day toolkit: | Tool | Purpose | |---|---| | `bash` | Persistent shell session (120 s default timeout). Persists `cd`, env vars, and aliases across calls. | | `find_files` | Find files or directories by glob (`*.md`, `**/*.ts`). Pass `include: "dirs"` to find folders. | | `search_files` | Search inside files for words, phrases, or regex (replacement for `grep`/`rg`). | | `read_file` | Read files or list directories. Vision-aware for JPEG/PNG/GIF when configured. | | `write_file` | Create or overwrite a file. | | `edit_file` | Apply targeted `str_replace` or `insert` edits. Read first. | | `memory` | Read or modify the long-term memory files (`USER.md`, `MEMORY.md`). | `sandboxConfig` controls OS-level sandboxing — see [Sandbox & Safety](/guide/sandbox-and-safety). ### `makeReadFileTool(sandboxConfig, imageConfig?, fileToolOptions?)` Stand-alone factory for `read_file` with vision support. Pass an `imageConfig` with `{ modelUrl, modelName, modelApiKey }` to enable image analysis through a vision-capable model. ### `makeMemoryTool({ memoryDir })` The `memory` tool exposes `read`, `add`, `replace`, and `remove` actions against `USER.md` and `MEMORY.md`. Per-file character caps (1375 / 2200) force curation rather than unbounded growth — when full, the agent must `replace` or `remove` to make room. See [Memory](/guide/memory). ### `makeSessionSearchTool({ search })` The `session_search` tool lets the agent search prior session transcripts and the archive for relevant past work. Pass a `SessionSearcher` implementation that returns ranked matches. ### `makeWebSearchTool()` and `makeWebFetchTool()` `web_search` requires `SEARCH_PROVIDER=linkup` or `SEARCH_PROVIDER=tavily` (plus the matching `LINKUP_API_KEY` / `TAVILY_API_KEY` env var). When unset, the tool returns a clear "not configured" error so the agent stops trying to call it. `web_fetch` is provider-agnostic and retrieves a full page when the agent already has a URL. `makeSearchTools()` is a convenience wrapper that returns `[web_search, web_fetch]`. ## Wiring tools into an agent ```ts const agent = new Agent({ dependencies: { userId: "user_123" }, tools: [ myTool, ...makeGeneralTools(), ...makeSearchTools(), ], // ... }); ``` The agent passes `dependencies` as the second argument to every tool function, so tools can share typed services (database handles, auth context, model clients) without globals. ## Filtering disabled tools When a search provider is unset, omit `web_search`/`web_fetch` from the `tools` array. The bundled gateway also strips references to disabled tools from the system prompt so the model does not try to call them. ## Path resolution helpers `resolveAgainstCwd(path, cwd)` and `memoryPathGuard(path, memoryDir)` are exported for custom tools that need the same sandboxed path semantics as the built-ins. ## See also - [Tool result contract](/framework/tool-result-contract) — the `{ok, ...}` envelope - [Hooks](/framework/hooks) — pre/post-tool callbacks for safety and logging - [User tools](/framework/user-tools) — load custom tools from `~/.osagent/.tools/` --- # Traces Source: https://docs.osagent.computer/framework/traces # Traces OSagent records each user turn as a structured JSONL entry on disk. Local-only by default, opt-out with one config flag. ## Where they live ``` ~/.osagent/.traces/.jsonl ``` One file per session. Each line is a `TraceEntry` — see [`packages/agent-framework-ts/src/trace.ts`](https://github.com/LocaiLabs/OSAgent/blob/dev/packages/agent-framework-ts/src/trace.ts) for the exact shape (it's a plain TypeScript interface; safer to read than to mirror in docs that drift). Roughly: ```jsonc { "timestamp": "2026-05-01T10:42:18.512Z", "session_id": "...", "turn": 7, "user_message": "...", "assistant_message": "...", "tool_calls": [{ "name": "...", "arguments": "...", "result": "...", "status": "ok|error|blocked", "duration_ms": 14 }], "model_name": "...", "latency_ms": 1830 } ``` The full system prompt is recorded once per session (on the first turn). ## Disabling ```json { "traces": { "enabled": false } } ``` Or delete `~/.osagent/.traces/`. ## Privacy controls `TraceWriter` accepts a privacy config — `redactPaths` (default on, replaces `$HOME` with `~`) and `excludeTools` (omit listed tools entirely). ## Export The framework exposes `exportSft` and `getTraceStats`. They produce multi-turn `{ messages: [...] }` shapes most SFT toolchains accept. Try them on your own data before relying on them for anything important. ## What this is for - Personal evals (replay your own past prompts against a new model). - Fine-tuning a smaller local model on your own usage patterns. - Debugging — every turn captures timing and the system prompt. It is **not** telemetry. Nothing is uploaded. ## See also - [Configuration](/guide/configuration) — `traces.*` - [Events](/framework/events) --- # User Tools Source: https://docs.osagent.computer/framework/user-tools # User Tools You can extend the agent with your own tools by dropping them into `~/.osagent/.tools/`. The framework discovers and loads them at startup. ::: warning Experimental in v0.1 The plugin loader works but the manifest schema and resolution rules will likely change before 1.0. Treat this as a sketch of where it's going, not a stable API. ::: ## Two layouts ### 1. Flat `.mjs` file ```js // ~/.osagent/.tools/uptime.mjs import { Tool } from "@locailabs/agent-framework"; import { execSync } from "node:child_process"; export default new Tool( async () => execSync("uptime").toString().trim(), { type: "function", function: { name: "uptime", description: "Show system uptime and load.", parameters: { type: "object", properties: {} }, }, }, ); ``` Default-export a `Tool` instance, or `{ tool: Tool }`. ### 2. Plugin directory ``` ~/.osagent/.tools/my-plugin/ ├── manifest.json └── tool.mjs ``` ```jsonc // manifest.json { "name": "my-plugin", "version": "1.0.0", "description": "What this plugin does", "requires": "0.1.0", "entry": "tool.mjs" } ``` The entry file follows the same shape as the flat layout. ## Loading When embedding the framework you can load user tools explicitly: ```ts import { loadUserTools, ensureUserToolsDir } from "@locailabs/agent-framework"; await ensureUserToolsDir(); const { tools, errors } = await loadUserTools(); const agent = new Agent({ tools: [...makeGeneralTools(), ...tools], }); ``` Plugins with invalid manifests are skipped at load time and logged. ## A few notes - User tools run **outside** the OS sandbox (the sandbox only wraps `bash`). Validate inputs and don't `eval` model-supplied code. - Returning a [tool result envelope](/framework/tool-result-contract) helps the model recover from errors. - If you find yourself wanting a one-off shell command, just let the model use `bash` instead. ## See also - [Tools](/framework/tools) - [Tool result contract](/framework/tool-result-contract) - [Hooks](/framework/hooks) --- # Contributing Source: https://docs.osagent.computer/contributing # Contributing Thanks for your interest in contributing to OSagent. The canonical contributor guide lives in [`CONTRIBUTING.md`](https://github.com/LocaiLabs/OSAgent/blob/dev/CONTRIBUTING.md) in the repo root. The short version is below — read the full file before opening a PR. ## Branch strategy ``` feature/* → dev (staging) → main (release) ``` - `dev` — default branch. All PRs target it. - `main` — release branch. Tags on `main` trigger builds. - `feature/*` — your working branch. Branched from `dev`, PR'd back to `dev`. ## Sign-off Every commit must include a DCO sign-off line: ``` Signed-off-by: Your Name ``` `git commit -s` adds this automatically. ## Local setup Prerequisites: - [Node.js](https://nodejs.org/) >= 18 - [Bun](https://bun.sh/) (for the CLI) - [llama-server](https://github.com/ggml-org/llama.cpp) on your `PATH` (only if you want to run a local model — `brew install llama.cpp` on macOS) Build and run: ```bash git clone https://github.com/LocaiLabs/OSAgent.git cd OSAgent npm install npm run build:framework cd packages/agent-gateway && npm run build && cd ../.. cd apps/cli bun install bun run start -- --config # first time only bun run start # subsequent runs ``` After pulling new changes, do a clean rebuild: ```bash rm -rf packages/agent-framework-ts/dist packages/agent-gateway/dist npm run build:framework cd packages/agent-gateway && npm run build && cd ../.. ``` ## Adding a tool, hook, or skill Quick checklists live in [`CONTRIBUTING.md`](https://github.com/LocaiLabs/OSAgent/blob/dev/CONTRIBUTING.md). For the API itself, see: - [Tools](/framework/tools) - [Hooks](/framework/hooks) - [Skills](/framework/skills) ## Style - **British spellings** in code comments, docs, UI strings, and commit messages. - Run `npm run test:framework` and `npm run lint:framework` before submitting. - Keep commits focused; never commit secrets. ## Code of Conduct This project follows the [Contributor Covenant](https://github.com/LocaiLabs/OSAgent/blob/dev/CODE_OF_CONDUCT.md). By participating you agree to uphold it. ## Reporting issues Use the issue templates on GitHub: - **Bug report** — something broken or unexpected - **Feature request** — suggest a new capability ## Security Please report vulnerabilities privately — see the [Security Policy](https://github.com/LocaiLabs/OSAgent/blob/dev/SECURITY.md). --- # OSagent Source: https://docs.osagent.computer/ # OSagent The local-first AI agent for your operating system. Built by [Locai Labs](https://locailabs.com). It runs entirely on your machine by default — no cloud services, no API keys, no data leaves your computer. Plug in a hosted provider only when you choose to. The CLI ships with built-in tools (`read_file`, `write_file`, `bash`, web search), persistent memory across sessions, and a skills system the agent extends as it learns. ## Quick Links | Topic | What it covers | | --- | --- | | 🚀 **[Installation](./guide/getting-started)** | Install in 60 seconds on macOS, Linux, or Windows | | 📖 **[What is OSagent?](./guide/what-is-osagent)** | The 5-minute introduction | | 🧩 **[Tools](./guide/tools)** | Built-in tools and how the agent uses them | | 📚 **[Skills](./guide/skills)** | On-demand knowledge the agent creates and reuses | | 🧠 **[Memory](./guide/memory)** | How OSagent remembers across sessions | | 🌐 **[Providers](./guide/providers)** | Local llama-server, OpenAI, Anthropic, and OpenAI-compatible endpoints | | ⚙️ **[Configuration](./guide/configuration)** | Config file, models, search providers, agent settings | | 🔒 **[Sandbox & Safety](./guide/sandbox-and-safety)** | Seatbelt on macOS, bubblewrap on Linux, hook-level safety checks | | 💻 **[macOS Desktop App](./guide/macos-app)** | Native SwiftUI app with floating overlay and global hotkey *(coming soon)* | | 🛠️ **[CLI Reference](./guide/cli-reference)** | All flags and REPL commands | | 🏗️ **[Architecture](./framework/architecture)** | How the pieces fit together | | 🧰 **[Build with the Framework](./framework/overview)** | Embed the agent loop in your own TypeScript app | | 🗺️ **[Roadmap](./guide/roadmap)** | What's shipping next | | 💬 **[Community](./guide/community)** | Discord, GitHub, contributing | | ❓ **[Troubleshooting](./guide/troubleshooting)** | Common issues and how to fix them | ## Key Features - **Local by default** — Downloads and runs open-weight GGUF models via [llama.cpp](https://github.com/ggerganov/llama.cpp). Your prompts and code stay on your machine unless you explicitly route to a cloud provider. - **Real tools, real safety** — Read, write, and patch files. Run shell commands. Search the web. Fetch pages. `bash` runs inside an OS sandbox (Seatbelt on macOS, bubblewrap on Linux) and hook-level checks catch dangerous patterns even when the sandbox is off. - **Persistent memory** — `~/.osagent/memory/USER.md` and `MEMORY.md` are plain markdown files you can read and edit. The agent reads and updates them through the `memory` tool. - **Skills system** — Procedural knowledge the agent creates after solving a task and reuses next time. Skills live in `~/.osagent/skills/` as portable markdown files. - **Bring your own model** — Drop any `.gguf` into `~/.osagent/.models/`, or point at any OpenAI-compatible endpoint (Ollama, vLLM, OpenAI, Anthropic, hosted gateways). - **Cross-platform** — CLI for macOS, Linux, and Windows. Native SwiftUI desktop app for macOS and a Tauri desktop for Windows and Linux are on the roadmap. - **Developer framework** — `@locailabs/agent-framework` is a standalone TypeScript library: pluggable model clients, custom tools, hooks, streaming, multi-turn conversations. - **Apache 2.0** — Inspect, fork, ship. Source on [GitHub](https://github.com/LocaiLabs/OSAgent). ## Install ::: code-group ```bash [macOS / Linux] curl -fsSL https://cli.osagent.computer/install.sh | sh ``` ```powershell [Windows (PowerShell)] irm https://cli.osagent.computer/install.ps1 | iex ``` ::: The installer downloads the CLI, installs `llama-server` if missing, adds everything to your PATH, and launches the setup wizard. See [Getting Started](./guide/getting-started) for the full walkthrough. ## For LLMs and coding agents Machine-readable entry points to these docs: - **[/llms.txt](https://docs.osagent.computer/llms.txt)** — curated index of every doc page with short descriptions. ~5 KB, safe to load into an LLM context. - **[/llms-full.txt](https://docs.osagent.computer/llms-full.txt)** — every doc page concatenated into one markdown file for one-shot ingestion. ~64 KB. Generated fresh on every deploy. Follows the [llmstxt.org](https://llmstxt.org) format. ---