# fugu
`fugu` is an OpenBSD-native AI coding agent — a small, privilege-separated
coding assistant written in C, in OpenBSD style, sandboxed with `pledge(2)` and
`unveil(2)`. It is a clean-room reimplementation (in spirit, not source) of the
TypeScript agent *pi* by Mario Zechner.
## Status
Functional. The five privilege-separated processes, the curses and line-mode
front ends, the streaming Anthropic agent loop, the file/shell/search and
brokered web tools, and the append-only session journal with resume, `/clear`
and `/compact` are all in place, with man pages and an OpenBSD port. The
behavior is exercised by the `regress/` suite (including `make`-driven
`pledge`/`unveil` sandbox checks, verifiable at the syscall level with
`ktrace`/`kdump`).
## Usage
fugu # start a session in the current project
fugu -l # list saved sessions
fugu -c # resume the most recent session
fugu -r <id> # resume a session by id
fugu -n # print the effective config (secrets redacted) and exit
In a session, type a message and press Enter; `/clear` resets the active
context, `/compact` replaces it with a model-written summary, and `/quit`
exits. Configuration and the Anthropic key live in `~/.fugu/fugu.conf` (mode
`0600`); see the `fugu(1)` and `fugu.conf(5)` manuals.
## Platform
**OpenBSD only.** fugu depends on `pledge(2)`, `unveil(2)`, `libtls`, `imsg(3)`,
base `curses`, and the BSD `make` build system. It deliberately does **not**
build on Linux or other systems — portability shims would undermine the security
model.
## Architecture
Five privilege-separated processes, each a separate binary that the parent
`fork`+`exec`s, communicating over `imsg(3)` socketpairs. The parent relays all
worker-to-worker messages (no direct worker-to-worker channels):
| binary | role | pledge |
|--------|------|--------|
| `fugu` | parent: coordinator + imsg relay; reads config, delegates secrets | `stdio proc` |
| `fugu-ui` | curses/line TUI; owns the tty and the session journal | `stdio tty` |
| `fugu-net` | libtls HTTPS to the Anthropic API; holds the API key | `stdio inet dns` |
| `fugu-exec` | file tools + `ksh`; no network | `stdio rpath wpath cpath proc exec` |
| `fugu-fetch` | libtls web search/fetch (Kagi); parses untrusted HTML in isolation | `stdio inet dns` |
`fugu-exec`'s execpromises omit `inet`, so neither it nor the commands it runs
can reach the network (opt in per project with `allow_subprocess_net`); its
`unveil` confines writes to the working tree. `fugu-ui` opens its journal under
`~/.fugu/sessions` while it briefly holds `rpath wpath cpath`, then narrows to
`stdio tty`.
Each role links only the libraries it needs (`libtls` only in net/fetch,
`curses` only in ui), so the untrusted-input processes never map code they don't
use. fugu runs entirely unprivileged (no root, not a daemon).
## Build (on OpenBSD)
make obj # optional
make
doas make install # installs under ${PREFIX:-/usr/local}
The OpenBSD port lives in the ports tree (not this repo), under
`mystuff/productivity/fugu`; build a package with `make package` there.
## Layout
src/common/ shared code: log, util, buf, json, imsgproto, http, sse, conf
src/parent/ fugu -> ${PREFIX}/bin (also installs the man pages)
src/ui/ fugu-ui -> ${PREFIX}/libexec/fugu
src/net/ fugu-net -> ${PREFIX}/libexec/fugu
src/exec/ fugu-exec -> ${PREFIX}/libexec/fugu
src/fetch/ fugu-fetch -> ${PREFIX}/libexec/fugu
man/ fugu.1, fugu.conf.5
etc/ fugu.conf.sample
regress/ unit, integration, and pledge/unveil sandbox tests
## License
ISC — see [LICENSE](LICENSE). Bundles the shared OpenBSD `log.c`/`log.h` (ISC,
© Henning Brauer). Inspired by *pi* (MIT, © Mario Zechner); no shared source.