Releases: mcanouil/oboro
Release list
0.8.2
Install
Quick install (script)
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash
# or pin this exact release
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.8.2The script picks the archive for your machine and verifies it against SHA256SUMS. It installs into /usr/local/bin when that is writable, otherwise into ~/.local/bin.
It needs bash and curl. On a minimal distribution such as Alpine, install them first with apk add bash curl.
Add --features ner for the build that also detects names not on any list (on Linux it needs glibc 2.39+). Then fetch its model:
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.8.2 --features ner
oboro models pull # about 348 MB, once, verified against pinned hashesDocker
docker volume create oboro-vault
docker run --rm \
-v oboro-vault:/vault \
-v "$PWD":/work -w /work \
--user "$(id -u):$(id -g)" \
ghcr.io/mcanouil/oboro:0.8.2 clean contract.docxThe vault volume is not optional. Without it, the mapping between placeholders and real values disappears with the container. The document can never be restored.
The ghcr.io/mcanouil/oboro:0.8.2-ner tag carries the ner build with the recognition model already inside the image. It finds names with no download and no network at run time.
A prebuilt binary
Pick the archive for your machine from the table below, then:
VERSION=0.8.2
TARGET=x86_64-unknown-linux-musl # or whichever row matches
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/oboro-${VERSION}-${TARGET}.tar.gz"
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/SHA256SUMS"
# Check it is what was published.
sha256sum --ignore-missing --check SHA256SUMS
tar -xzf "oboro-${VERSION}-${TARGET}.tar.gz"
install -m 0755 oboro /usr/local/bin/oboroOn macOS, shasum -a 256 --ignore-missing --check SHA256SUMS does the same job.
With Rust already installed
cargo install --git https://github.com/mcanouil/oboro --tag 0.8.2From source, with the optional features
The default binaries read .txt, .md, .docx, .xlsx and text-based .pdf. They find structured values and anything on your denylist.
They do not find names you have not listed, and they do not read images.
For names, use a -ner archive from the table below (then run oboro models pull), the :0.8.2-ner image, or a source build.
Images need the Tesseract system libraries, so reading them stays a source build:
cargo build --release --features ner # names and organisations, then: oboro models pull
cargo build --release --features ocr # images and scanned pages, needs TesseractIf names are not being redacted, a default build is almost certainly why.
oboro doctor reports what any build can do.
To build the optional features without setting up the system libraries yourself, use the devcontainer. It carries the pinned toolchain, Tesseract and the OCR libraries:
docker build -f .devcontainer/Dockerfile -t oboro-dev .devcontainer
docker run --rm -it -v "$PWD":/work -w /work -u vscode oboro-dev \
cargo build --release --features "ner,ocr"In Visual Studio Code or a GitHub Codespace, reopen the folder in the container instead.
Verify what you downloaded
Beyond the checksum, every archive carries build provenance. Use it to confirm the archive came from this repository's workflow, not from somewhere else:
gh attestation verify "oboro-0.8.2-x86_64-unknown-linux-musl.tar.gz" \
--repo mcanouil/oboroThis tool checks the model it downloads against a pinned hash before using it.
It would be inconsistent to ask you to trust its own binaries on sight.
Which archive is which
| Archive | For |
|---|---|
x86_64-unknown-linux-musl |
Linux on Intel or AMD. Statically linked, so any distribution, glibc version or Alpine. |
aarch64-unknown-linux-musl |
Linux on ARM, including most cloud instances. Statically linked. |
aarch64-apple-darwin |
macOS on Apple silicon. |
x86_64-pc-windows-msvc |
Windows on Intel or AMD. |
x86_64-unknown-linux-gnu-ner |
Linux on Intel or AMD, with name recognition. Needs glibc 2.39+ (Ubuntu 24.04+, Debian 13+). |
aarch64-unknown-linux-gnu-ner |
Linux on ARM, with name recognition. Needs glibc 2.39+. |
aarch64-apple-darwin-ner |
macOS on Apple silicon, with name recognition. |
The -ner archives detect names once you fetch the model with oboro models pull. The others are the smaller default build.
The Windows archive is a .zip; extract it with Expand-Archive.
Documentation
Changes
- docs: Rewrite documentation prose in plain, direct sentences.
0.8.1
Install
Quick install (script)
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash
# or pin this exact release
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.8.1The script picks the archive for your machine, verifies it against SHA256SUMS, and installs into /usr/local/bin when writable, otherwise ~/.local/bin.
It needs bash and curl; on a minimal distribution such as Alpine, install them first with apk add bash curl.
Add --features ner for the build that also finds untold names (on Linux it needs glibc 2.39+), then fetch its model:
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.8.1 --features ner
oboro models pull # about 348 MB, once, verified against pinned hashesDocker
docker volume create oboro-vault
docker run --rm \
-v oboro-vault:/vault \
-v "$PWD":/work -w /work \
--user "$(id -u):$(id -g)" \
ghcr.io/mcanouil/oboro:0.8.1 clean contract.docxThe vault volume is not optional.
Without it the mapping between placeholders and real values disappears with the container, and the document can never be restored.
The ghcr.io/mcanouil/oboro:0.8.1-ner tag carries the ner build with the recognition model already inside the image, so untold names are found with no download and no network at run time.
A prebuilt binary
Pick the archive for your machine from the table below, then:
VERSION=0.8.1
TARGET=x86_64-unknown-linux-musl # or whichever row matches
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/oboro-${VERSION}-${TARGET}.tar.gz"
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/SHA256SUMS"
# Check it is what was published.
sha256sum --ignore-missing --check SHA256SUMS
tar -xzf "oboro-${VERSION}-${TARGET}.tar.gz"
install -m 0755 oboro /usr/local/bin/oboroOn macOS, shasum -a 256 --ignore-missing --check SHA256SUMS does the same job.
With Rust already installed
cargo install --git https://github.com/mcanouil/oboro --tag 0.8.1From source, with the optional features
The default binaries read .txt, .md, .docx, .xlsx and text-based .pdf, and find structured values and anything on your denylist.
They do not find names nobody told them about, and they do not read images.
Names need a -ner archive from the table below (then oboro models pull), the :0.8.1-ner image, or a source build.
Images need the Tesseract system libraries, so reading them stays a source build:
cargo build --release --features ner # names and organisations, then: oboro models pull
cargo build --release --features ocr # images and scanned pages, needs TesseractIf names are not being redacted, a default build is almost certainly why.
oboro doctor reports what any build can do.
To build the optional features without setting up the system libraries on your machine, use the devcontainer, which carries the pinned toolchain, Tesseract and the OCR libraries:
docker build -f .devcontainer/Dockerfile -t oboro-dev .devcontainer
docker run --rm -it -v "$PWD":/work -w /work -u vscode oboro-dev \
cargo build --release --features "ner,ocr"In Visual Studio Code or a GitHub Codespace, reopen the folder in the container instead.
Verify what you downloaded
Beyond the checksum, every archive carries build provenance, so you can confirm it came from this repository's workflow and not from somewhere else:
gh attestation verify "oboro-0.8.1-x86_64-unknown-linux-musl.tar.gz" \
--repo mcanouil/oboroThis tool checks the model it downloads against a pinned hash before using it.
It would be inconsistent to ask you to trust its own binaries on sight.
Which archive is which
| Archive | For |
|---|---|
x86_64-unknown-linux-musl |
Linux on Intel or AMD. Statically linked, so any distribution, glibc version or Alpine. |
aarch64-unknown-linux-musl |
Linux on ARM, including most cloud instances. Statically linked. |
aarch64-apple-darwin |
macOS on Apple silicon. |
x86_64-pc-windows-msvc |
Windows on Intel or AMD. |
x86_64-unknown-linux-gnu-ner |
Linux on Intel or AMD, with name recognition. Needs glibc 2.39+ (Ubuntu 24.04+, Debian 13+). |
aarch64-unknown-linux-gnu-ner |
Linux on ARM, with name recognition. Needs glibc 2.39+. |
aarch64-apple-darwin-ner |
macOS on Apple silicon, with name recognition. |
The -ner archives find untold names once the model is fetched with oboro models pull; the others are the smaller default build.
The Windows archive is a .zip; extract it with Expand-Archive.
Documentation
Changes
- fix: Make
docs/install.ps1run the way it is advertised. Both published one-liners failed in 0.8.0: the file's byte order mark came back inside the string fetched over HTTP and broke the opening line. A failure now also reports what went wrong rather than a missingPath. CI runs the script the way the documentation says to, so this cannot ship again. (#113)
0.8.0
Warning
The Windows PowerShell installer published in this release cannot run.
docs/install.ps1 carries a byte order mark, which Invoke-RestMethod returns inside the string as a literal U+FEFF, so the opening line is read as an unknown command and nothing after it executes.
Both advertised forms fail.
Use 0.8.1 instead, where it is fixed.
Everything else in this release is unaffected, install.sh included.
Install
Quick install (script)
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash
# or pin this exact release
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.8.0The script picks the archive for your machine, verifies it against SHA256SUMS, and installs into /usr/local/bin when writable, otherwise ~/.local/bin.
It needs bash and curl; on a minimal distribution such as Alpine, install them first with apk add bash curl.
Add --features ner for the build that also finds untold names (on Linux it needs glibc 2.39+), then fetch its model:
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.8.0 --features ner
oboro models pull # about 348 MB, once, verified against pinned hashesDocker
docker volume create oboro-vault
docker run --rm \
-v oboro-vault:/vault \
-v "$PWD":/work -w /work \
--user "$(id -u):$(id -g)" \
ghcr.io/mcanouil/oboro:0.8.0 clean contract.docxThe vault volume is not optional.
Without it the mapping between placeholders and real values disappears with the container, and the document can never be restored.
The ghcr.io/mcanouil/oboro:0.8.0-ner tag carries the ner build with the recognition model already inside the image, so untold names are found with no download and no network at run time.
A prebuilt binary
Pick the archive for your machine from the table below, then:
VERSION=0.8.0
TARGET=x86_64-unknown-linux-musl # or whichever row matches
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/oboro-${VERSION}-${TARGET}.tar.gz"
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/SHA256SUMS"
# Check it is what was published.
sha256sum --ignore-missing --check SHA256SUMS
tar -xzf "oboro-${VERSION}-${TARGET}.tar.gz"
install -m 0755 oboro /usr/local/bin/oboroOn macOS, shasum -a 256 --ignore-missing --check SHA256SUMS does the same job.
With Rust already installed
cargo install --git https://github.com/mcanouil/oboro --tag 0.8.0From source, with the optional features
The default binaries read .txt, .md, .docx, .xlsx and text-based .pdf, and find structured values and anything on your denylist.
They do not find names nobody told them about, and they do not read images.
Names need a -ner archive from the table below (then oboro models pull), the :0.8.0-ner image, or a source build.
Images need the Tesseract system libraries, so reading them stays a source build:
cargo build --release --features ner # names and organisations, then: oboro models pull
cargo build --release --features ocr # images and scanned pages, needs TesseractIf names are not being redacted, a default build is almost certainly why.
oboro doctor reports what any build can do.
To build the optional features without setting up the system libraries on your machine, use the devcontainer, which carries the pinned toolchain, Tesseract and the OCR libraries:
docker build -f .devcontainer/Dockerfile -t oboro-dev .devcontainer
docker run --rm -it -v "$PWD":/work -w /work -u vscode oboro-dev \
cargo build --release --features "ner,ocr"In Visual Studio Code or a GitHub Codespace, reopen the folder in the container instead.
Verify what you downloaded
Beyond the checksum, every archive carries build provenance, so you can confirm it came from this repository's workflow and not from somewhere else:
gh attestation verify "oboro-0.8.0-x86_64-unknown-linux-musl.tar.gz" \
--repo mcanouil/oboroThis tool checks the model it downloads against a pinned hash before using it.
It would be inconsistent to ask you to trust its own binaries on sight.
Which archive is which
| Archive | For |
|---|---|
x86_64-unknown-linux-musl |
Linux on Intel or AMD. Statically linked, so any distribution, glibc version or Alpine. |
aarch64-unknown-linux-musl |
Linux on ARM, including most cloud instances. Statically linked. |
aarch64-apple-darwin |
macOS on Apple silicon. |
x86_64-pc-windows-msvc |
Windows on Intel or AMD. |
x86_64-unknown-linux-gnu-ner |
Linux on Intel or AMD, with name recognition. Needs glibc 2.39+ (Ubuntu 24.04+, Debian 13+). |
aarch64-unknown-linux-gnu-ner |
Linux on ARM, with name recognition. Needs glibc 2.39+. |
aarch64-apple-darwin-ner |
macOS on Apple silicon, with name recognition. |
The -ner archives find untold names once the model is fetched with oboro models pull; the others are the smaller default build.
The Windows archive is a .zip; extract it with Expand-Archive.
Documentation
Changes
- fix: Name the agent hook
oboro uninstallwill not remove, rather than reporting everything as gone. The command sweeps the two settings filesoboro hook installwrites,.claude/settings.local.jsonfor a project and~/.claude/settings.jsonfor a user, butoboro doctorreads a third, a project's shared.claude/settings.json, so a hook pasted there by hand survived an uninstall that had just said it removed everything and went on running. That file stays untouched, since it is committed and shared with colleagues and Oboro never wrote it, but it is now listed in the uninstall report alongside the plugin and the Docker volume, andoboro doctormarks the hook as one an uninstall leaves behind. (#111) - feat: Add
docs/install.ps1, the Windows counterpart toinstall.sh:powershell -ExecutionPolicy ByPass -c "irm https://m.canouil.dev/oboro/install.ps1 | iex"downloads thex86_64-pc-windows-msvcrelease archive, verifies it againstSHA256SUMS(and against build provenance withOBORO_VERIFY_PROVENANCE=1), and installs into%LOCALAPPDATA%\Programs\oboro\bin, adding it to the userPATHif missing; no administrator rights needed. Arm64 and--features ner/--features ocrare refused, since no prebuilt Windows build carries them, andcargo build --release --features <name>is pointed at instead. Published alongsideinstall.shindocs/_quarto.yml, with anInvoke-ScriptAnalyzerlint job onwindows-latest. (#109) - feat: Add
oboro uninstall, which removes everything the tool wrote: completion scripts, the agent hooks and skill in both scopes, the vault, the recognition model, and the binary itself. It prints everything that would go and asks to confirm;--dry-runstops after printing,--yesskips the prompt, and--keep-vaultleaves the vault and its key in place. A settings file keeps everything but Oboro's own hook, ending as{}rather than being deleted, and the running binary removes itself on macOS and Linux; on Windows, which locks a running image, the path and the command to finish the job are printed instead. (#108)
0.7.0
Install
Quick install (script)
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash
# or pin this exact release
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.7.0The script picks the archive for your machine, verifies it against SHA256SUMS, and installs into /usr/local/bin when writable, otherwise ~/.local/bin.
It needs bash and curl; on a minimal distribution such as Alpine, install them first with apk add bash curl.
Add --features ner for the build that also finds untold names (on Linux it needs glibc 2.39+), then fetch its model:
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.7.0 --features ner
oboro models pull # about 348 MB, once, verified against pinned hashesDocker
docker volume create oboro-vault
docker run --rm \
-v oboro-vault:/vault \
-v "$PWD":/work -w /work \
--user "$(id -u):$(id -g)" \
ghcr.io/mcanouil/oboro:0.7.0 clean contract.docxThe vault volume is not optional.
Without it the mapping between placeholders and real values disappears with the container, and the document can never be restored.
The ghcr.io/mcanouil/oboro:0.7.0-ner tag carries the ner build with the recognition model already inside the image, so untold names are found with no download and no network at run time.
A prebuilt binary
Pick the archive for your machine from the table below, then:
VERSION=0.7.0
TARGET=x86_64-unknown-linux-musl # or whichever row matches
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/oboro-${VERSION}-${TARGET}.tar.gz"
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/SHA256SUMS"
# Check it is what was published.
sha256sum --ignore-missing --check SHA256SUMS
tar -xzf "oboro-${VERSION}-${TARGET}.tar.gz"
install -m 0755 oboro /usr/local/bin/oboroOn macOS, shasum -a 256 --ignore-missing --check SHA256SUMS does the same job.
With Rust already installed
cargo install --git https://github.com/mcanouil/oboro --tag 0.7.0From source, with the optional features
The default binaries read .txt, .md, .docx, .xlsx and text-based .pdf, and find structured values and anything on your denylist.
They do not find names nobody told them about, and they do not read images.
Names need a -ner archive from the table below (then oboro models pull), the :0.7.0-ner image, or a source build.
Images need the Tesseract system libraries, so reading them stays a source build:
cargo build --release --features ner # names and organisations, then: oboro models pull
cargo build --release --features ocr # images and scanned pages, needs TesseractIf names are not being redacted, a default build is almost certainly why.
oboro doctor reports what any build can do.
To build the optional features without setting up the system libraries on your machine, use the devcontainer, which carries the pinned toolchain, Tesseract and the OCR libraries:
docker build -f .devcontainer/Dockerfile -t oboro-dev .devcontainer
docker run --rm -it -v "$PWD":/work -w /work -u vscode oboro-dev \
cargo build --release --features "ner,ocr"In Visual Studio Code or a GitHub Codespace, reopen the folder in the container instead.
Verify what you downloaded
Beyond the checksum, every archive carries build provenance, so you can confirm it came from this repository's workflow and not from somewhere else:
gh attestation verify "oboro-0.7.0-x86_64-unknown-linux-musl.tar.gz" \
--repo mcanouil/oboroThis tool checks the model it downloads against a pinned hash before using it.
It would be inconsistent to ask you to trust its own binaries on sight.
Which archive is which
| Archive | For |
|---|---|
x86_64-unknown-linux-musl |
Linux on Intel or AMD. Statically linked, so any distribution, glibc version or Alpine. |
aarch64-unknown-linux-musl |
Linux on ARM, including most cloud instances. Statically linked. |
aarch64-apple-darwin |
macOS on Apple silicon. |
x86_64-pc-windows-msvc |
Windows on Intel or AMD. |
x86_64-unknown-linux-gnu-ner |
Linux on Intel or AMD, with name recognition. Needs glibc 2.39+ (Ubuntu 24.04+, Debian 13+). |
aarch64-unknown-linux-gnu-ner |
Linux on ARM, with name recognition. Needs glibc 2.39+. |
aarch64-apple-darwin-ner |
macOS on Apple silicon, with name recognition. |
The -ner archives find untold names once the model is fetched with oboro models pull; the others are the smaller default build.
The Windows archive is a .zip; extract it with Expand-Archive.
Documentation
Changes
Breaking changes
- feat!: Accept
--vaultand--keyafter the command that opens a vault rather than before it, sooboro --vault work.db clean notes/becomesoboro clean --vault work.db notes/.OBORO_VAULTandOBORO_KEY_FILEare unaffected, and so is every spelling that already named the command first, which is every one the documentation ever showed. Declaring the pair once at the root made them global, and global meant listed under every subcommand's help, includingoboro skill show,oboro models pullandoboro hook install, none of which ever open a vault: they were accepted there and quietly ignored, and the completion script offered them there too, so the help, the completion and the behaviour disagreed in the same place. They are now declared on the commands that use them, still global so that one declaration onmapcoversmap listandmap purgewithout being repeated on either, and the commands that never open a vault refuse them instead of taking them and doing nothing. (#102)
Features
- feat: Print a shell completion script with
oboro completions <shell>, forbash,zsh,fish,elvishandpowershell. The script goes to standard output and the destination it belongs in goes to standard error alongside it, so one command answers both halves of a question a generated script only ever answers half of:oboro completions zsh > ~/.oh-my-zsh/custom/completions/_oborowrites a file with nothing in front of it for the shell to trip over, the instructions still reach the terminal where they are useful at that moment, and2>/dev/nulldrops them for anyone scripting the command. Each shell is told its own convention rather than a generic sentence, including the leading underscore in the zsh filename and the two linescompinitneeds when the directory is not already on$fpath; oh-my-zsh is named first, because it puts$ZSH_CUSTOM/completionson$fpathand runscompinititself, so those users are finished once the file is written and the generic advice would send them to edit~/.zshrcfor no effect. The script is generated under the name the command carries rather than the name it was invoked by, so one written from a build directory or from a renamed copy still completes the installed name. (#101) - feat: Install a completion script with
oboro completions <shell> --install, which writes it where the shell reads it and edits your shell's configuration only where the file alone is not enough, inside a managed block that re-running replaces and--uninstallremoves.--dry-runreports every path either would touch. The shell is taken from$SHELLwhen it is left out, and printing to standard output is still what happens without a flag, so a redirect, or a pipe intoInvoke-Expression, works as before. PowerShell refuses to be installed and says what to run instead, since it evaluates its script from$PROFILErather than reading a file. - feat: Install zsh completions to oh-my-zsh's custom directory, or to Homebrew's
share/zsh/site-functionswhen the prefix has one and it is writable, before falling back to~/.zfuncwith anfpathline. The first two are on$fpathalready, so nothing is added to~/.zshrcfor them. Homebrew's prefix is read from$HOMEBREW_PREFIX, or found at/opt/homebrewor/usr/local, rather than by runningbrew, which acurl | bashpipe often cannot reach. - fix: Report a stale copy that cannot be removed, rather than failing on it. One of the places swept is Homebrew's prefix, which is outside the home directory and may belong to another user, and a file there is not reason enough to fail an install that has otherwise worked. Nothing is ever removed with elevated rights.
- feat: Keep an install where it is. A script already on disk is the one that is updated, wherever it is, even once the machine has gained oh-my-zsh, Homebrew or bash-completion and a first install would now choose elsewhere; copies in the other known places are swept so none is left to shadow it. Moving one is
--uninstallfollowed by a fresh install, and an unchanged script is reported asAlready currentrather than rewritten. - feat: Report in
oboro doctorwhether the completion scripts on disk still match the binary. A completion script is a copy of the command surface from the moment it was generated, so a release that adds a command leaves it offering the old set and nothing otherwise says so; each one is regenerated and compared byte for byte, which answers that exactly with no version to parse, and a stale one is followed by the command that rewrites it. Every conventional destination is looked in whatever$SHELLsays, since that variable is wrong often enough to matter and a place holding no file costs no line.docs/install.shlooks in the same places and prints the same command when it finds one, being the moment that knows a version changed. It now compares each script against the binary it has just installed rather than reporting every script it finds, so reinstalling the same version says nothing at all, and a first install stays quiet. (#101) - feat: Restrict the vault database and key on Windows with
icacls, dropping every inherited grant and giving the current account a...
0.6.0
Install
Quick install (script)
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash
# or pin this exact release
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.6.0The script picks the archive for your machine, verifies it against SHA256SUMS, and installs into /usr/local/bin when writable, otherwise ~/.local/bin.
It needs bash and curl; on a minimal distribution such as Alpine, install them first with apk add bash curl.
Add --features ner for the build that also finds untold names (on Linux it needs glibc 2.39+), then fetch its model:
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.6.0 --features ner
oboro models pull # about 348 MB, once, verified against pinned hashesDocker
docker volume create oboro-vault
docker run --rm \
-v oboro-vault:/vault \
-v "$PWD":/work -w /work \
--user "$(id -u):$(id -g)" \
ghcr.io/mcanouil/oboro:0.6.0 clean contract.docxThe vault volume is not optional.
Without it the mapping between placeholders and real values disappears with the container, and the document can never be restored.
The ghcr.io/mcanouil/oboro:0.6.0-ner tag carries the ner build with the recognition model already inside the image, so untold names are found with no download and no network at run time.
A prebuilt binary
Pick the archive for your machine from the table below, then:
VERSION=0.6.0
TARGET=x86_64-unknown-linux-musl # or whichever row matches
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/oboro-${VERSION}-${TARGET}.tar.gz"
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/SHA256SUMS"
# Check it is what was published.
sha256sum --ignore-missing --check SHA256SUMS
tar -xzf "oboro-${VERSION}-${TARGET}.tar.gz"
install -m 0755 oboro /usr/local/bin/oboroOn macOS, shasum -a 256 --ignore-missing --check SHA256SUMS does the same job.
With Rust already installed
cargo install --git https://github.com/mcanouil/oboro --tag 0.6.0From source, with the optional features
The default binaries read .txt, .md, .docx, .xlsx and text-based .pdf, and find structured values and anything on your denylist.
They do not find names nobody told them about, and they do not read images.
Names need a -ner archive from the table below (then oboro models pull), the :0.6.0-ner image, or a source build.
Images need the Tesseract system libraries, so reading them stays a source build:
cargo build --release --features ner # names and organisations, then: oboro models pull
cargo build --release --features ocr # images and scanned pages, needs TesseractIf names are not being redacted, a default build is almost certainly why.
oboro doctor reports what any build can do.
To build the optional features without setting up the system libraries on your machine, use the devcontainer, which carries the pinned toolchain, Tesseract and the OCR libraries:
docker build -f .devcontainer/Dockerfile -t oboro-dev .devcontainer
docker run --rm -it -v "$PWD":/work -w /work -u vscode oboro-dev \
cargo build --release --features "ner,ocr"In Visual Studio Code or a GitHub Codespace, reopen the folder in the container instead.
Verify what you downloaded
Beyond the checksum, every archive carries build provenance, so you can confirm it came from this repository's workflow and not from somewhere else:
gh attestation verify "oboro-0.6.0-x86_64-unknown-linux-musl.tar.gz" \
--repo mcanouil/oboroThis tool checks the model it downloads against a pinned hash before using it.
It would be inconsistent to ask you to trust its own binaries on sight.
Which archive is which
| Archive | For |
|---|---|
x86_64-unknown-linux-musl |
Linux on Intel or AMD. Statically linked, so any distribution, glibc version or Alpine. |
aarch64-unknown-linux-musl |
Linux on ARM, including most cloud instances. Statically linked. |
aarch64-apple-darwin |
macOS on Apple silicon. |
x86_64-unknown-linux-gnu-ner |
Linux on Intel or AMD, with name recognition. Needs glibc 2.39+ (Ubuntu 24.04+, Debian 13+). |
aarch64-unknown-linux-gnu-ner |
Linux on ARM, with name recognition. Needs glibc 2.39+. |
aarch64-apple-darwin-ner |
macOS on Apple silicon, with name recognition. |
The -ner archives find untold names once the model is fetched with oboro models pull; the others are the smaller default build.
There is no Windows build.
The code that creates the vault key readable only by you is Unix-specific, and shipping a build where that quietly does nothing would misrepresent what the tool guarantees.
Documentation
Changes
Features
- fix: Skip a byte order mark at the head of an
.eml. Windows tooling writes one, RFC 5322 has no place for it, and the parser read it as the beginning of the first header's name, so that header stopped being one and was dropped whole.Fromis written first more often than anything else and is the densest identifying header a message has, so a name and an address reached nothing while the message still read as though it had been sanitised. (#98) - feat: Read
.emlinput, so an email reaches the detectors instead of being refused. The headers a person writes and reads are rendered first, then every part holding text: taking the bodies from the parts themselves rather than from the parser's own idea of what a mail client would display is what stops amultipart/relatedwhose HTML root is not its first part being read as headers alone. An HTML body has a line break put before every element other than the inline ones, because the flattener breaks a line on<br>and a closing</p>and on nothing else, and Gmail composes one<div>per line with no whitespace between the tags; naming the elements that run on, rather than the ones that break, keeps an element nobody thought of from welding two values into one that matches no rule. Amailto:ortel:link target is lifted into the text, since flattening discards attributes. A body is told from an attachment by its disposition rather than by carrying a filename, since a client that labels the HTML it displays with aname=is still displaying it. HTML the flattener cannot follow, an unclosed<head>or comment among it, is read by stripping its tags instead of being dropped. Every attachment is named, by its type alone when it has no filename, and its bytes are never read; every copy of a header written more than once is read; a forwarded message is followed; and a body whose transfer encoding will not decode fails rather than being read short. A parsed message is taken apart a level at a time rather than dropped, so a file of eighty thousand stacked forwards is read instead of overflowing the stack and aborting. Charsets are decoded single-byte and multi-byte alike, so a Shift-JIS message is read as written. (#97) - docs: Say that
.jsonand.yamlare not read. The formats section named the older Office and OpenDocument extensions the tool turns away, and the parts of a.pptxand a.odtit misses, but never these, so a reader checking whether their file was covered learnt nothing about them. A file with one of those extensions is refused rather than read partially, and the message names the formats the build does read. (#96) - docs: Give the changelog page a single heading. It supplies its own title, and then included this file, which opens with a heading and a line of boilerplate written for reading it on its own, so the page carried two level-one headings and said twice what it was. The preamble is cut on the way in and this file is left as it is. (#92)
- feat: Refuse to start
oboro mcpuntil you have said what itscleantool may read, with--root DIRnaming a directory it may read within, repeatable, or--unconfinedto let it read any file you can read. The caller over this protocol is a model rather than you, and a client that offers to remember its approval turns one careless click into a standing licence, so reading the whole disk is not something to arrive at by leaving an argument off. A root is resolved once at startup, so a symbolic link inside one that points outside it is refused rather than followed, and a root that does not exist or is not a directory stops the server while there is still a person watching rather than becoming a refusal to every later call; a path outside every root is refused in the same words whether or not it exists, so the refusals cannot be used to map a disk. (#91) - docs: Say what
oboro mcpdoes not guarantee, beside the tool list where you decide whether to add it and at length in Limitations: it offers the agent a tool rather than intercepting anything, so unlike the hook it depends on the agent choosing that tool and its worth is reach into clients that have no hook system; cleaning is not confinement, since passwords, API keys and access tokens are not detected kinds and pass through as written, so a root bounds which files can be reached rather than promising anything about what is in them, and for a client with no file access of its own this server is the read capability it did not otherwise have; and the absence of a restore tool is not itself protection, since in any client with a shell the model can runoboro restore --stdoutoroboro map list --revealwithout the server being involved at all. (#90) - feat: Serve the Model Context Protocol on standard input and output with
oboro mcp, JSON-RPC 2.0 one message to a line, so an agent in a client with no hook system can ask for a cleaned file instead of reading the file itself. Two tools are offered:clean, which takes a path and answers with that file's text as placeholders, one content block per part and one block per sheet under a## <sheet name>heading for a workbook, t...
0.5.0
Install
Quick install (script)
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash
# or pin this exact release
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.5.0The script picks the archive for your machine, verifies it against SHA256SUMS, and installs into /usr/local/bin when writable, otherwise ~/.local/bin.
It needs bash and curl; on a minimal distribution such as Alpine, install them first with apk add bash curl.
Add --features ner for the build that also finds untold names (on Linux it needs glibc 2.39+), then fetch its model:
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.5.0 --features ner
oboro models pull # about 348 MB, once, verified against pinned hashesDocker
docker volume create oboro-vault
docker run --rm \
-v oboro-vault:/vault \
-v "$PWD":/work -w /work \
--user "$(id -u):$(id -g)" \
ghcr.io/mcanouil/oboro:0.5.0 clean contract.docxThe vault volume is not optional.
Without it the mapping between placeholders and real values disappears with the container, and the document can never be restored.
The ghcr.io/mcanouil/oboro:0.5.0-ner tag carries the ner build with the recognition model already inside the image, so untold names are found with no download and no network at run time.
A prebuilt binary
Pick the archive for your machine from the table below, then:
VERSION=0.5.0
TARGET=x86_64-unknown-linux-musl # or whichever row matches
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/oboro-${VERSION}-${TARGET}.tar.gz"
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/SHA256SUMS"
# Check it is what was published.
sha256sum --ignore-missing --check SHA256SUMS
tar -xzf "oboro-${VERSION}-${TARGET}.tar.gz"
install -m 0755 oboro /usr/local/bin/oboroOn macOS, shasum -a 256 --ignore-missing --check SHA256SUMS does the same job.
With Rust already installed
cargo install --git https://github.com/mcanouil/oboro --tag 0.5.0From source, with the optional features
The default binaries read .txt, .md, .docx, .xlsx and text-based .pdf, and find structured values and anything on your denylist.
They do not find names nobody told them about, and they do not read images.
Names need a -ner archive from the table below (then oboro models pull), the :0.5.0-ner image, or a source build.
Images need the Tesseract system libraries, so reading them stays a source build:
cargo build --release --features ner # names and organisations, then: oboro models pull
cargo build --release --features ocr # images and scanned pages, needs TesseractIf names are not being redacted, a default build is almost certainly why.
oboro doctor reports what any build can do.
To build the optional features without setting up the system libraries on your machine, use the devcontainer, which carries the pinned toolchain, Tesseract and the OCR libraries:
docker build -f .devcontainer/Dockerfile -t oboro-dev .devcontainer
docker run --rm -it -v "$PWD":/work -w /work -u vscode oboro-dev \
cargo build --release --features "ner,ocr"In Visual Studio Code or a GitHub Codespace, reopen the folder in the container instead.
Verify what you downloaded
Beyond the checksum, every archive carries build provenance, so you can confirm it came from this repository's workflow and not from somewhere else:
gh attestation verify "oboro-0.5.0-x86_64-unknown-linux-musl.tar.gz" \
--repo mcanouil/oboroThis tool checks the model it downloads against a pinned hash before using it.
It would be inconsistent to ask you to trust its own binaries on sight.
Which archive is which
| Archive | For |
|---|---|
x86_64-unknown-linux-musl |
Linux on Intel or AMD. Statically linked, so any distribution, glibc version or Alpine. |
aarch64-unknown-linux-musl |
Linux on ARM, including most cloud instances. Statically linked. |
aarch64-apple-darwin |
macOS on Apple silicon. |
x86_64-unknown-linux-gnu-ner |
Linux on Intel or AMD, with name recognition. Needs glibc 2.39+ (Ubuntu 24.04+, Debian 13+). |
aarch64-unknown-linux-gnu-ner |
Linux on ARM, with name recognition. Needs glibc 2.39+. |
aarch64-apple-darwin-ner |
macOS on Apple silicon, with name recognition. |
The -ner archives find untold names once the model is fetched with oboro models pull; the others are the smaller default build.
There is no Windows build.
The code that creates the vault key readable only by you is Unix-specific, and shipping a build where that quietly does nothing would misrepresent what the tool guarantees.
Documentation
Changes
Features
- docs: Say what the tests on recognised scans actually assert, now that they also check the text came back rather than only that nothing survived cleaning; two of the six rendered lines is still a long way from measuring how much of a page was recognised, and the page says so. (#85)
- docs: Say that a PDF page can be read short without anything saying so. A page that cannot be processed is caught and the document refused, but the extractor drops text whose shape it does not recognise rather than failing on it, so a page can come back with less on it than it holds. The per-page floor catches a page reduced to almost nothing; one that loses a line or two is used as it is. (#80)
- feat: Read
.pptxpresentations, taking the text of every slide in presentation order, followed by every speaker note and then every comment, so a deck reaches the detectors instead of being refused; slide layouts and masters are left out, since their text is template prompt material rather than anything the author wrote. (#81) - feat: Read a scanned PDF rather than refusing it, on a build with
--features ocr: the images on its pages go through the recogniser, covering both the way a scanner stores a colour page (DCTDecode) and the way it stores a bilevel one (CCITTFaxDecode), needing no library beyond the Tesseract the feature already asks for; text drawn on the page is kept alongside what is recognised, so a scan with a searchable text layer does not lose half of itself, and a page is refused by name rather than half read when its image is in a codec that cannot be handed over, when a filter is layered over that codec, or when it carries no image at all. (#75) - feat: Install both halves with one command,
oboro skill install --with-hooks, which writes the skill and names both hooks in the same scope, asks once and shows both files it would write, and plans both before writing either, so a scope that refuses one installs neither; drop the flag for the skill alone, or useoboro hook installfor the hooks alone. (#74) - feat: Install the hooks and the skill in one step from a Claude Code plugin marketplace, with
/plugin marketplace add mcanouil/oborothen/plugin install oboro@oboro; the plugin is this repository, so it ships the skill the binary carries rather than a copy of it, and its hooks go through a wrapper that withholds the result and refuses the call when nooborois onPATH, rather than leaving a machine unprotected while looking installed. (#74) - feat: Report an enabled Oboro plugin in
oboro doctor, naming the settings file that enables it, and say of the hooks and the skill that the plugin carries them rather than that they are missing, since what it carries lives in its own files and reporting it as absent would send you to install what you already have. (#74) - feat: Say so when
oboro hook install, oroboro skill install --with-hooks, is about to name hooks a plugin already carries, since both copies would then run on every matching tool call. (#74) - docs: Name
npx skills add mcanouil/oboroas the skill-only path, for agents other than Claude Code, saying plainly that it installs the explanation and not the machine and that it symlinks the skill, which is whyoboro skill installafterwards refuses the path rather than overwriting it. (#74) - feat: Name both hooks in your agent's settings with
oboro hook install, so wiring Oboro into Claude Code no longer means pasting JSON by hand;--projectwrites.claude/settings.local.jsonand--userwrites~/.claude/settings.json, without either it asks which, and--dry-runprints the settings as they would end up. - feat: Merge into the settings file rather than rewriting it: every other key keeps its place and its order, another tool's hooks on the same event are left where they are, and a hook already naming
oboro hookis left exactly as you wrote it, matcher included, so a matcher you narrowed by hand survives an install. - feat: Refuse rather than replace a settings file Oboro cannot merge into, naming it: invalid JSON, a root that is not an object, or a
hooksentry of the wrong shape. Nothing is written through a symbolic link, and the file is replaced by renaming a complete one into place. - feat: Say so when the hooks just installed name an
oborothat is not onPATH, since a hook the agent cannot run fails closed on every matching tool call. - feat: Tell an agent what the hooks have done to what it reads, with
oboro skill install, which writes a skill explaining that[[EMAIL_1]]is a real value it cannot see rather than a bug or a template, and that writing the placeholder back verbatim is correct becausepre-tool-userestores it; the text is compiled into the binary so it cannot drift from the hooks it describes,oboro skill showprints it without writing anything, andoboro doctorreports both scopes. - feat: Ask which scope to install the skill into rather than guessing, since the wrong scope fails silently;
--projectand--userskip the question, and with no terminal to ask the command fails and names both flags. - feat: Leave an edited skill where it is, writing what ...
0.4.0
Install
Quick install (script)
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash
# or pin this exact release
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.4.0The script picks the archive for your machine, verifies it against SHA256SUMS, and installs into /usr/local/bin when writable, otherwise ~/.local/bin.
It needs bash and curl; on a minimal distribution such as Alpine, install them first with apk add bash curl.
Add --features ner for the build that also finds untold names (on Linux it needs glibc 2.39+), then fetch its model:
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.4.0 --features ner
oboro models pull # about 348 MB, once, verified against pinned hashesDocker
docker volume create oboro-vault
docker run --rm \
-v oboro-vault:/vault \
-v "$PWD":/work -w /work \
--user "$(id -u):$(id -g)" \
ghcr.io/mcanouil/oboro:0.4.0 clean contract.docxThe vault volume is not optional.
Without it the mapping between placeholders and real values disappears with the container, and the document can never be restored.
The ghcr.io/mcanouil/oboro:0.4.0-ner tag carries the ner build with the recognition model already inside the image, so untold names are found with no download and no network at run time.
A prebuilt binary
Pick the archive for your machine from the table below, then:
VERSION=0.4.0
TARGET=x86_64-unknown-linux-musl # or whichever row matches
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/oboro-${VERSION}-${TARGET}.tar.gz"
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/SHA256SUMS"
# Check it is what was published.
sha256sum --ignore-missing --check SHA256SUMS
tar -xzf "oboro-${VERSION}-${TARGET}.tar.gz"
install -m 0755 oboro /usr/local/bin/oboroOn macOS, shasum -a 256 --ignore-missing --check SHA256SUMS does the same job.
With Rust already installed
cargo install --git https://github.com/mcanouil/oboro --tag 0.4.0From source, with the optional features
The default binaries read .txt, .md, .docx, .xlsx and text-based .pdf, and find structured values and anything on your denylist.
They do not find names nobody told them about, and they do not read images.
Names need a -ner archive from the table below (then oboro models pull), the :0.4.0-ner image, or a source build.
Images need the Tesseract system libraries, so reading them stays a source build:
cargo build --release --features ner # names and organisations, then: oboro models pull
cargo build --release --features ocr # images and scanned pages, needs TesseractIf names are not being redacted, a default build is almost certainly why.
oboro doctor reports what any build can do.
To build the optional features without setting up the system libraries on your machine, use the devcontainer, which carries the pinned toolchain, Tesseract and the OCR libraries:
docker build -f .devcontainer/Dockerfile -t oboro-dev .devcontainer
docker run --rm -it -v "$PWD":/work -w /work -u vscode oboro-dev \
cargo build --release --features "ner,ocr"In Visual Studio Code or a GitHub Codespace, reopen the folder in the container instead.
Verify what you downloaded
Beyond the checksum, every archive carries build provenance, so you can confirm it came from this repository's workflow and not from somewhere else:
gh attestation verify "oboro-0.4.0-x86_64-unknown-linux-musl.tar.gz" \
--repo mcanouil/oboroThis tool checks the model it downloads against a pinned hash before using it.
It would be inconsistent to ask you to trust its own binaries on sight.
Which archive is which
| Archive | For |
|---|---|
x86_64-unknown-linux-musl |
Linux on Intel or AMD. Statically linked, so any distribution, glibc version or Alpine. |
aarch64-unknown-linux-musl |
Linux on ARM, including most cloud instances. Statically linked. |
aarch64-apple-darwin |
macOS on Apple silicon. |
x86_64-unknown-linux-gnu-ner |
Linux on Intel or AMD, with name recognition. Needs glibc 2.39+ (Ubuntu 24.04+, Debian 13+). |
aarch64-unknown-linux-gnu-ner |
Linux on ARM, with name recognition. Needs glibc 2.39+. |
aarch64-apple-darwin-ner |
macOS on Apple silicon, with name recognition. |
The -ner archives find untold names once the model is fetched with oboro models pull; the others are the smaller default build.
There is no Windows build.
The code that creates the vault key readable only by you is Unix-specific, and shipping a build where that quietly does nothing would misrepresent what the tool guarantees.
Documentation
Changes
Features
- feat: Write each workbook sheet to its own TSV file (
book.xlsxwith a sheetClientsbecomesbook.Clients.clean.tsv), keeping the tabular structure openable in a spreadsheet tool instead of flattening the workbook into one markdown file; sheet names are sanitised for the filesystem, redacted like filenames whenredact_filenamesis on, and numbered apart when they collide. - feat: Read
.csvand.tsvfiles, passed through as plain text so the cleaned output stays a valid tabular file. - feat: Name each output after its input's format, so
data.csvbecomesdata.clean.csvanddata.tsvbecomesdata.clean.tsvwhile documents keep.clean.md;restoreneeds no change since it rewrites placeholders in any text file. - feat: Refuse any two inputs whose sanitised outputs would land on one file, including sheet outputs, case-folded names, and aliased spellings of one path, before the refused document's values are stored in the vault.
- feat: Match a denylist term against its exact case with
case_sensitive = true, so a short name such asBellis redacted without also redacting the ordinary wordbell; terms still ignore case by default, and no regular expression is needed to make one case-sensitive. - feat: Match street addresses in the three word orders languages write them in, so
10 Downing Street,Hauptstraße 5and12 Kerkstraatare read alongside12 rue de la Paix, with no language declared anywhere; postcodes now cover the British, Canadian, Dutch and American formats as well as five-digit ones, while a bare four-digit postcode stays unmatched on purpose since it cannot be told apart from a year. - feat: Replace
default_regionwithregions, a list of region codes whose national phone number formats are read, so a document holding numbers from several countries is handled at once; a number valid in any listed region is redacted, an international+number is read whatever the list holds, and an unknown code is now refused by name instead of silently ignored. Without the key the region comes from the environment's locale, andoboro doctorreports which regions are in force and where they came from. A configuration still usingdefault_regionis refused, naming the unknown key. - feat: Choose the languages Tesseract reads images in from
ocr_languages, or from whatever trained data is installed when it is unset, replacing the hard-codedfra+engthat made French trained data a requirement for reading any image at all; asking for a language with no trained data now says so and lists what is installed. - feat: Tidy text and markdown input before cleaning it, so trailing spaces, runs of blank lines and blank lines at either end of the file do not survive into the output; indentation is kept, since it carries markdown structure, and
.csvand.tsvare passed through byte for byte.
0.3.0
Install
Quick install (script)
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash
# or pin this exact release
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.3.0The script picks the archive for your machine, verifies it against SHA256SUMS, and installs into /usr/local/bin when writable, otherwise ~/.local/bin.
It needs bash and curl; on a minimal distribution such as Alpine, install them first with apk add bash curl.
Add --features ner for the build that also finds untold names (on Linux it needs glibc 2.39+), then fetch its model:
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.3.0 --features ner
oboro models pull # about 348 MB, once, verified against pinned hashesDocker
docker volume create oboro-vault
docker run --rm \
-v oboro-vault:/vault \
-v "$PWD":/work -w /work \
--user "$(id -u):$(id -g)" \
ghcr.io/mcanouil/oboro:0.3.0 clean contract.docxThe vault volume is not optional.
Without it the mapping between placeholders and real values disappears with the container, and the document can never be restored.
The ghcr.io/mcanouil/oboro:0.3.0-ner tag carries the ner build with the recognition model already inside the image, so untold names are found with no download and no network at run time.
A prebuilt binary
Pick the archive for your machine from the table below, then:
VERSION=0.3.0
TARGET=x86_64-unknown-linux-musl # or whichever row matches
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/oboro-${VERSION}-${TARGET}.tar.gz"
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/SHA256SUMS"
# Check it is what was published.
sha256sum --ignore-missing --check SHA256SUMS
tar -xzf "oboro-${VERSION}-${TARGET}.tar.gz"
install -m 0755 oboro /usr/local/bin/oboroOn macOS, shasum -a 256 --ignore-missing --check SHA256SUMS does the same job.
With Rust already installed
cargo install --git https://github.com/mcanouil/oboro --tag 0.3.0From source, with the optional features
The default binaries read .txt, .md, .docx, .xlsx and text-based .pdf, and find structured values and anything on your denylist.
They do not find names nobody told them about, and they do not read images.
Names need a -ner archive from the table below (then oboro models pull), the :0.3.0-ner image, or a source build.
Images need the Tesseract system libraries, so reading them stays a source build:
cargo build --release --features ner # names and organisations, then: oboro models pull
cargo build --release --features ocr # images and scanned pages, needs TesseractIf names are not being redacted, a default build is almost certainly why.
oboro doctor reports what any build can do.
To build the optional features without setting up the system libraries on your machine, use the devcontainer, which carries the pinned toolchain, Tesseract and the OCR libraries:
docker build -f .devcontainer/Dockerfile -t oboro-dev .devcontainer
docker run --rm -it -v "$PWD":/work -w /work -u vscode oboro-dev \
cargo build --release --features "ner,ocr"In Visual Studio Code or a GitHub Codespace, reopen the folder in the container instead.
Verify what you downloaded
Beyond the checksum, every archive carries build provenance, so you can confirm it came from this repository's workflow and not from somewhere else:
gh attestation verify "oboro-0.3.0-x86_64-unknown-linux-musl.tar.gz" \
--repo mcanouil/oboroThis tool checks the model it downloads against a pinned hash before using it.
It would be inconsistent to ask you to trust its own binaries on sight.
Which archive is which
| Archive | For |
|---|---|
x86_64-unknown-linux-musl |
Linux on Intel or AMD. Statically linked, so any distribution, glibc version or Alpine. |
aarch64-unknown-linux-musl |
Linux on ARM, including most cloud instances. Statically linked. |
aarch64-apple-darwin |
macOS on Apple silicon. |
x86_64-unknown-linux-gnu-ner |
Linux on Intel or AMD, with name recognition. Needs glibc 2.39+ (Ubuntu 24.04+, Debian 13+). |
aarch64-unknown-linux-gnu-ner |
Linux on ARM, with name recognition. Needs glibc 2.39+. |
aarch64-apple-darwin-ner |
macOS on Apple silicon, with name recognition. |
The -ner archives find untold names once the model is fetched with oboro models pull; the others are the smaller default build.
There is no Windows build.
The code that creates the vault key readable only by you is Unix-specific, and shipping a build where that quietly does nothing would misrepresent what the tool guarantees.
Documentation
Changes
Features
- feat: Publish prebuilt ner binaries (
x86_64-unknown-linux-gnu-ner,aarch64-unknown-linux-gnu-ner,aarch64-apple-darwin-ner), installable withinstall.sh --features ner; the Linux ones need glibc 2.39+ since ONNX Runtime has no musl build. - feat: Publish a ner Docker image under
-nersuffixed tags (ner,<version>-ner,main-ner) with the recognition model baked in and hash-verified at image build, so untold names are found with no download and no network at run time.
0.2.0
Install
Quick install (script)
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash
# or pin this exact release
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.2.0The script picks the archive for your machine, verifies it against SHA256SUMS, and installs into /usr/local/bin when writable, otherwise ~/.local/bin.
It needs bash and curl; on a minimal distribution such as Alpine, install them first with apk add bash curl.
Docker
docker volume create oboro-vault
docker run --rm \
-v oboro-vault:/vault \
-v "$PWD":/work -w /work \
--user "$(id -u):$(id -g)" \
ghcr.io/mcanouil/oboro:0.2.0 clean contract.docxThe vault volume is not optional.
Without it the mapping between placeholders and real values disappears with the container, and the document can never be restored.
A prebuilt binary
Pick the archive for your machine from the table below, then:
VERSION=0.2.0
TARGET=x86_64-unknown-linux-musl # or whichever row matches
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/oboro-${VERSION}-${TARGET}.tar.gz"
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/SHA256SUMS"
# Check it is what was published.
sha256sum --ignore-missing --check SHA256SUMS
tar -xzf "oboro-${VERSION}-${TARGET}.tar.gz"
install -m 0755 oboro /usr/local/bin/oboroOn macOS, shasum -a 256 --ignore-missing --check SHA256SUMS does the same job.
With Rust already installed
cargo install --git https://github.com/mcanouil/oboro --tag 0.2.0From source, with the optional features
The published binaries are the default build.
They read .txt, .md, .docx, .xlsx and text-based .pdf, and find structured values and anything on your denylist.
They do not find names nobody told them about, and they do not read images.
Names link ONNX Runtime, fetched over the network while building; images need the Tesseract system libraries. Both are compiled in rather than shipped:
cargo build --release --features ner # names and organisations, then: oboro models pull
cargo build --release --features ocr # images and scanned pages, needs TesseractIf names are not being redacted, this is almost certainly why.
oboro doctor reports what any build can do.
To build the optional features without setting up the system libraries on your machine, use the devcontainer, which carries the pinned toolchain, Tesseract and the OCR libraries:
docker build -f .devcontainer/Dockerfile -t oboro-dev .devcontainer
docker run --rm -it -v "$PWD":/work -w /work -u vscode oboro-dev \
cargo build --release --features "ner,ocr"In Visual Studio Code or a GitHub Codespace, reopen the folder in the container instead.
Verify what you downloaded
Beyond the checksum, every archive carries build provenance, so you can confirm it came from this repository's workflow and not from somewhere else:
gh attestation verify "oboro-0.2.0-x86_64-unknown-linux-musl.tar.gz" \
--repo mcanouil/oboroThis tool checks the model it downloads against a pinned hash before using it.
It would be inconsistent to ask you to trust its own binaries on sight.
Which archive is which
| Archive | For |
|---|---|
x86_64-unknown-linux-musl |
Linux on Intel or AMD. Statically linked, so any distribution, glibc version or Alpine. |
aarch64-unknown-linux-musl |
Linux on ARM, including most cloud instances. Statically linked. |
aarch64-apple-darwin |
macOS on Apple silicon. |
There is no Windows build.
The code that creates the vault key readable only by you is Unix-specific, and shipping a build where that quietly does nothing would misrepresent what the tool guarantees.
Documentation
Changes
Features
- feat: Accept a directory argument to
cleanandreview, cleaning every supported file it holds;--recursivedescends into subdirectories, unsupported files are skipped and counted, and--outputmirrors the input tree. - feat: Redact PII found in the input filename so it no longer leaks into the output name (
jean@example.com.txtbecomesEMAIL_1.clean.md), sharing placeholders with the document body; on by default and disabled withredact_filenames = falseinoboro.toml.
0.1.0
Install
Quick install (script)
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash
# or pin this exact release
curl -fsSL https://m.canouil.dev/oboro/install.sh | bash -s -- --version 0.1.0The script picks the archive for your machine, verifies it against SHA256SUMS, and installs into /usr/local/bin when writable, otherwise ~/.local/bin.
It needs bash and curl; on a minimal distribution such as Alpine, install them first with apk add bash curl.
Docker
docker volume create oboro-vault
docker run --rm \
-v oboro-vault:/vault \
-v "$PWD":/work -w /work \
--user "$(id -u):$(id -g)" \
ghcr.io/mcanouil/oboro:0.1.0 clean contract.docxThe vault volume is not optional.
Without it the mapping between placeholders and real values disappears with the container, and the document can never be restored.
A prebuilt binary
Pick the archive for your machine from the table below, then:
VERSION=0.1.0
TARGET=x86_64-unknown-linux-musl # or whichever row matches
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/oboro-${VERSION}-${TARGET}.tar.gz"
curl -fsSLO "https://github.com/mcanouil/oboro/releases/download/${VERSION}/SHA256SUMS"
# Check it is what was published.
sha256sum --ignore-missing --check SHA256SUMS
tar -xzf "oboro-${VERSION}-${TARGET}.tar.gz"
install -m 0755 oboro /usr/local/bin/oboroOn macOS, shasum -a 256 --ignore-missing --check SHA256SUMS does the same job.
With Rust already installed
cargo install --git https://github.com/mcanouil/oboro --tag 0.1.0From source, with the optional features
The published binaries are the default build.
They read .txt, .md, .docx, .xlsx and text-based .pdf, and find structured values and anything on your denylist.
They do not find names nobody told them about, and they do not read images.
Both need system libraries, so they are compiled in rather than shipped:
cargo build --release --features ner # names and organisations, then: oboro models pull
cargo build --release --features ocr # images and scanned pages, needs TesseractIf names are not being redacted, this is almost certainly why.
oboro doctor reports what any build can do.
To build the optional features without setting up the system libraries on your machine, use the devcontainer, which carries the pinned toolchain, Tesseract and the OCR libraries:
docker build -f .devcontainer/Dockerfile -t oboro-dev .devcontainer
docker run --rm -it -v "$PWD":/work -w /work -u vscode oboro-dev \
cargo build --release --features "ner,ocr"In Visual Studio Code or a GitHub Codespace, reopen the folder in the container instead.
Verify what you downloaded
Beyond the checksum, every archive carries build provenance, so you can confirm it came from this repository's workflow and not from somewhere else:
gh attestation verify "oboro-0.1.0-x86_64-unknown-linux-musl.tar.gz" \
--repo mcanouil/oboroThis tool checks the model it downloads against a pinned hash before using it.
It would be inconsistent to ask you to trust its own binaries on sight.
Which archive is which
| Archive | For |
|---|---|
x86_64-unknown-linux-musl |
Linux on Intel or AMD. Statically linked, so any distribution, glibc version or Alpine. |
aarch64-unknown-linux-musl |
Linux on ARM, including most cloud instances. Statically linked. |
aarch64-apple-darwin |
macOS on Apple silicon. |
There is no Windows build.
The code that creates the vault key readable only by you is Unix-specific, and shipping a build where that quietly does nothing would misrepresent what the tool guarantees.
Documentation
Changes
Features
- feat: Replace sensitive values in a document with stable placeholders, so the same value always becomes the same placeholder within a vault.
- feat: Keep the mapping in a local vault encrypted with AES-256-GCM and indexed by a keyed hash, so the database alone reveals neither the values nor whether a guessed value is present.
- feat: Bind each placeholder's sequence into the encryption, and create the vault, key and write-ahead-log sidecars owner-only, so a swapped row is detected and the files stay readable only by you.
- feat: Clean a document to placeholders with
clean, and put the real values back into a model's answer withrestore, both reading and writing standard input and output. - feat: Step through every detection with
review, a terminal screen for accepting or rejecting each one before anything is written. - feat: Inspect and wipe the mapping with
map listandmap purge, and report the vault, configuration, supported formats and network use withdoctor. - feat: Detect emails, phone numbers, IBANs, payment cards, SIREN, SIRET, IP addresses and French addresses, each confirmed by a checksum or parser rather than a pattern alone.
- feat: Find names, organisations and addresses with a local multilingual recognition model, built with
--features nerand fetched bymodels pull, which verifies downloads against pinned hashes. - feat: Configure an allowlist, a denylist and custom identifier patterns through
oboro.toml, with accented case folded so an entry such asSociété GénéralematchesSOCIÉTÉ GÉNÉRALE. - feat: Read
.txt,.md,.docxincluding its headers, footers, footnotes and comments,.xlsx, and text-based.pdf, plus images through Tesseract when built with--features ocr. - feat: Refuse a PDF whose pages yield almost no text, rather than producing output that looks sanitised but was never read.
- feat: Publish a Docker image, a single static binary on
distroless/staticwith no shell and no network capability, and read the vault and key paths fromOBORO_VAULTandOBORO_KEY_FILEso a container can point them at a mounted volume. - feat: Install with a script that downloads the prebuilt binary and verifies it against the release checksums, or with prebuilt binaries that carry build provenance you can check with
gh attestation verify.