Tree


.gitignorecommits | blame
.scratch/
AGENTS.mdcommits | blame
CONTEXT.mdcommits | blame
LICENSEcommits | blame
Makefilecommits | blame
README.mdcommits | blame
clean-check*commits | blame
docs/
etc/
man/
regress/
run-fugu*commits | blame
src/

README.md

# 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.