Terminal and iPhone
An assistant that keeps things to itself.
Tacet turns your notes into a spreadsheet, reads what changed in your repository and runs a quick script, all on the machine in front of you. There is no account to create and no server on the other end. Install it, fetch a model once, and it works with the wifi switched off.
- Free, MIT licensed
- Works with the network off
- No account, no telemetry
- macOS, Linux, Windows, iPhone
That is the whole interface. You type, Tacet answers, and each tool it used leaves a line you can read.
Install
The script installs Rust's toolchain if cargo is missing, builds Tacet with the right feature for your machine, then fetches the model and opens your first chat. It checks you have the memory for the model before spending the bandwidth on it, because being killed by the kernel three minutes into a download is a bad first impression.
curl -fsSL https://usetacet.com/install.sh | sh
Doing it yourself. cargo install tacet-cli --features metal on Apple silicon, which uses the GPU and is about twice as fast. --features candle everywhere else, on CPU. Without either flag you still get a working binary, it just cannot run a model. If you would rather not compile anything, the releases page carries prebuilt binaries for macOS on Apple silicon and Intel, Linux on x86_64 and arm64, and Windows, with a SHA256SUMS file beside them.
Keep the flag when you upgrade. Cargo does not remember it. A binary installed without it refuses to answer rather than making something up: it names the missing feature and exits non-zero. tacet --version prints the engine in brackets, so you can always see which build you have.
Your own weights work as they are. Point TACET_MODEL at any GGUF file or drop it in ~/models/. There is no separate tokenizer file to find: Tacet reads the vocabulary, merges and token types out of the GGUF itself, so a file from Ollama or LM Studio loads unchanged.
Nothing checks for updates on its own. tacet update asks GitHub when you run it, and that is the only command that talks to GitHub at all. A few turns into your first session the shell asks once whether it may look daily, and writes your answer down.
Thirteen tools, no commands to learn
You write what you want in plain language. Every action that touches your disk leaves a receipt on screen, like the ones below.
Documents that are really documents
The OOXML is written by hand in this repository, so an .xlsx from Tacet arrives with a working =SUM() in the cell instead of a number someone pasted there.
It reads your repository
Ask what changed and Tacet reads the diff and writes the commit message for you. The git tool is read only: status, log, diff and show. It cannot commit, push, or move a branch.
Code runs behind a sandbox
run_code goes through sandbox-exec on macOS and bwrap on Linux, with the network cut. If no sandbox is available the tool is removed from the catalog instead of running unprotected, so the model is never handed a bare interpreter.
It remembers, in a file you can open
Tell it something worth keeping and it writes a note to disk, then brings it back when the note is relevant. Sessions are kept too, so tacet --continue picks up where you stopped.
The full catalog on a fresh install: calculate, time, calendar, read_document, create_document, edit_document, find_file, run_code, write_code, git, remember, archive and checksum. Anything with reach past your working directory is an addon you install on purpose, and until you do, its tools are not in the catalog the model is shown at all.
A call that has started cannot finish invalidly
The hard part of a local assistant is not running the model. It is getting a small model to produce a call the schema will accept, then executing it without handing anything away.
The grammar masks the logits
Once the model emits calculate(, a pushdown automaton decides which tokens are legal next and blanks the rest. Malformed JSON, a field that is not in the schema, a number outside its range: none of them can be produced. Sampling runs after masking, so no sampling setting gets around it.
And it has to end
A valid prefix used to be able to wander. One model wrote a correct calendar(...) call and then emitted whitespace for twelve minutes, because whitespace was legal there and legal again straight after. Consecutive whitespace is bounded now, and a constrained generation is capped at 2048 tokens against a largest observed real call of 1523.
Where the guarantee stops
The grammar arms after name(, so it says nothing about a call that never starts that way. A model can still write the right tool and the right arguments in a shape nobody taught it. A separate layer recovers those, and the gap is written down rather than papered over.
| Gate | What it rejects |
|---|---|
| Name | a tool that is not in the catalog, so the model cannot invent a callable |
| Schema | arguments that do not validate, even if the grammar was somehow bypassed |
| Approval | outbound data in a session that has already touched personal data |
| Cancel | anything at all, the moment you interrupt the turn |
The numbers, with the machine they came from
Most of the green numbers in the repository come from a mock engine and measure Tacet's own logic in milliseconds. Those are the wrong numbers for the question people actually ask, so here is the run on real weights: Qwen3-4B-Instruct-2507 at Q4_K_M on Metal, 184 cases in English and Turkish, 44 minutes, re-measured on 6 September 2026.
| Axis | Result |
|---|---|
| Tool selection | 139 / 160 · 86.9% |
| Irrelevance gate | 24 / 24 · 100% |
| Step chain | 169 / 190 · 88.9% |
| Answer quality | 40 / 47 · 85.1% |
Read the irrelevance gate first. Those are twenty-four messages that must not reach a tool, and none of them did. An assistant that fires a tool at "thanks, that's all" is worse than no assistant, and that is the failure this number rules out. Three of the four axes went up since the last baseline, and the comparator still refuses to call that an improvement: ten cases fixed, four broken, not distinguishable from no change at 95%. It is published as a new baseline rather than as a win.
And against someone else's cases
Every table above is this project grading itself on questions it wrote. So three categories of the Berkeley Function Calling Leaderboard were run through the same engine, prompt, router and grammar, using BFCL's own function definitions instead of Tacet's tools.
| BFCL v4 category | Cases | Expected | Result |
|---|---|---|---|
irrelevance | 237 | call nothing | 84.4% |
live_irrelevance | 871 | call nothing | 77.8% |
live_relevance | 16 | call something | 81.2% |
This is not a leaderboard submission and the numbers are not comparable to the published board, which scores through its own harness and parser. What it answers is narrower and more useful: given someone else's questions and someone else's functions, how often does this stack invent a call. It found a real bug on its eighth case, which is the argument for running outside cases at all. The full run, and what the translation cost.
What the grammar is worth
Running the same calls twice with the automaton on and off — same prompt, same sampler, same cap — a 4B goes from writing a malformed call about one time in five to never writing one, and correct calls go from 76.9% to 97.4%. On a 0.6B the correct rate does not move at all, because the automaton fixes the syntax of a call to the wrong tool exactly as faithfully as it fixes a right one. Valid is syntax. Correct is judgement. The three-model table.
There is more in the docs than belongs on a landing page: four models on one rented RTX 3090, seven languages measured against cases written natively in each, every failure counted and named, and the four ways the scoring itself turned out to be wrong before it was fixed.
The silent instrument is the network
Tacet is the mark in a score that tells a player they are silent for this passage. Here the player is your network card, and the claim is checkable rather than promised.
Two crates may open a socket
The HTTP dependency appears in exactly two manifests in the workspace, and grep -v '^\s*#' crates/*/Cargo.toml | grep ureq is the whole audit. There is a test that runs the same audit as a failing build, scanning every source file rather than just the library code, so nobody can reach a socket through std::net either.
Addons are absent, not disabled
Web search, HTTP, a shell, a database and the clipboard are addons you install on purpose. Until then their tools are missing from the catalog the model sees, so it cannot call them, mention them, or claim it did.
Dependencies you can read in an afternoon
serde, serde_json, thiserror, clap, crossterm and ureq, plus three more behind the inference feature that is off by default. The zip, deflate, CRC32 and OOXML writing are hand written, and so is the MCP client. What the full list honestly means, including the two C builds that come along transitively.
Every tool execution is also written to a receipt file by code, never by the model, which cannot reach the file through any tool. Each line carries the SHA-256 of the previous hash plus its own payload, so deleting or editing one line breaks every hash after it. tacet log verifies the whole chain on each run and says so out loud.
Honest about the platforms
A privacy tool that overstates its coverage is not a privacy tool. This is the state of each platform as it was actually measured, not as CI reports it.
| Platform | State |
|---|---|
| macOS (arm64) | Verified. The full suite runs here: build, clippy with warnings denied, tests, eval. |
| Linux | The sandbox is off on a default install. On a stock Ubuntu 24.04 an ordinary user cannot start bwrap, so run_code and write_code are simply absent from the catalog rather than running unprotected. The shell says so on startup and names the one sysctl that changes it. With the restriction lifted, 1069 tests pass against a real sandbox, including the ones that check the network is really cut. |
| Windows | Measured on a real machine, not a runner. The workspace builds and 1037 tests pass. One thing CI cannot see: a clean Windows has no C compiler, so the build stops until you install one. That is the real prerequisite, not the MSVC linker it looks like. |
Still unmeasured, and worth saying out loud: nobody has sat down and held a conversation with the interactive shell on Linux or on Windows. If you do, the most useful thing you can send is what broke.
Tacet is on the App Store
The phone app shares the stance of the terminal app and none of its code. The model is the one Apple ships with the system, running on the device, so there is no account and it still answers in airplane mode.
Tacet: Private AI Assistant
- Reads the Excel, Word, PDF and CSV files you attach, and writes spreadsheets back with real formulas.
- Arithmetic and date arithmetic go through a tool rather than the model's head, and a reply carrying a number the tools never produced is caught before you see it.
- Calendar, reminders and contacts are asked for in the moment a task needs them, with the reason on screen one beat before the system dialog.
- Every tool call appears as a chip whose text the tool wrote, never the model. Tap it for the raw input and output.
- Nine languages, with Turkish as the first market and its casing rules handled explicitly everywhere strings are compared.
Six mechanisms, not a sentence in a prompt
"Nothing leaves without your approval" is a promise that only means something if it is built out of code that can be tested. On iOS it is six things that compose, and a model-free self test of roughly 1200 assertions gates every merge on them.
- Network monopoly. Exactly two source files in the app may name a networking API. A static scan over the whole tree enforces it on every CI run and fails if it scanned fewer than 100 files.
- Gates closed by default, as a type. The value that describes what is open has every property false, and the session builder defaults to it, so a new call site that says nothing builds no web tool.
- The profile split is structural. The two profiles that can reach outside contain no personal-data tool at all, so the model cannot read your calendar and write it into an outbound argument in one step.
- Taint. A tool declares whether it touches personal data. Once one has run, the session is marked, and the mark survives a context rebuild. Only starting a new chat clears it.
- The approval sheet shows the exact text. Not a category, not a summary. Four outcomes get four different sentences back to the model, so it can never tell you that you declined something you were never asked about.
- An outbound ledger. Every attempt to send, whether it went or not, is appended to a hash-chained record that the model can never read and that clearing your chat history does not touch.
The app also has a screen listing what it cannot do: weak world knowledge, losing the thread in a long chat, no images, no voice output, no access to your mail or messages. An Android version is being built next, with a model you choose and download yourself, since there is no system model to lean on there. No date yet.
Ollama runs models. Tacet runs your day.
Ollama, LM Studio and llama.cpp are good at what they do: pick a model, get a chat window. Tacet sits one level up and gladly runs the same open models. The difference is everything wrapped around them.
| Capability | Model runners | Tacet |
|---|---|---|
| Chat with a local model | ✓ | ✓ |
| No account, no telemetry | ✓ | ✓ |
| A malformed tool call cannot be generated | — | ✓ |
| Reads your git diff and writes the commit message | — | ✓ |
| Runs your code in a sandbox with the network cut | — | ✓ |
| Writes real Word and Excel files with live formulas | — | ✓ |
| Notes on disk that you can read and edit | — | ✓ |
| A receipt on screen for every action | — | ✓ |
| A published score for tool selection, on named weights | — | ✓ |
A 40 000-row spreadsheet never enters the model either. The tool that read it puts the data in a store and hands back a short summary plus a reference, and the next tool fetches it by that reference. The context window becomes a budget rather than a ceiling.
Skills, servers, and a benchmark for your own tools
Skills
A skill is a Markdown file with trigger phrases and a short piece of guidance. When a message matches, exactly one skill is fenced into that turn's prompt and never into the system instruction. That distinction was measured: guidance in the system instruction pushed a small model toward explaining the task instead of calling the tool. Drop yours in ~/.tacet/skills/.
MCP servers
List servers you run yourself in ~/.tacet/mcp.json and their tools join the catalog. They pass through the same four gates as the built-in ones, so a remote tool gets no privilege a local tool does not have. tacet mcp try calls one by hand before you trust it.
Benchmark your own tools
The eval suite measures this project. A benchmark is the other direction: a JSON file you write, run against the tools your machine actually has. tacet bench check runs before any model does and tells you whether the expected tool would even reach the prompt, which costs nothing and catches the case that would otherwise be scored as a model failure forever.
Ask why it chose that
Nine tools reach the model out of however many exist. tacet why "..." prints that ranking without loading any weights: which tools would be offered, in what order, and what matched. When a case goes red, this is what tells you whether to blame the routing or the model. How the ranking works, including the 48 KiB classifier that rides along with the trigger list.
Frequently asked
What is Tacet?
How is Tacet different from Ollama and LM Studio?
Does Tacet send my data anywhere?
grep, and a test in the repository fails the build if it stops being true. One honest asterisk: if you install the shell addon and put curl on its allow list, you have handed a program the network yourself. That is why shell sits behind the approval gate.Which model does it use?
Qwen3-4B and Qwen3-4B-Instruct-2507 are two different models and every number on this page was measured on the second. A smaller qwen2.5-3b is in the catalog too, and you can add your own entries in ~/.tacet/packages.json.Do I need a GPU?
metal feature uses the GPU and is roughly twice as fast. Everywhere else candle runs on CPU. Worth knowing before you rent a card: on a 3090, one stream already saturates it, so running several copies of a suite side by side wins nothing. Batching into a single forward pass is the thing that scales, from 124 tokens per second at batch 1 to 504 at batch 32.Is there an iPhone app?
Can it search the web?
web-search addon and point it at a SearXNG instance you run, either locally under Docker or at an address you already have. There is no default search provider and no shared endpoint. Once a turn has read personal data, any call that could carry it off the machine stops and asks you first.Does it work in Turkish?
How do I install it?
curl -fsSL https://usetacet.com/install.sh | sh on macOS or Linux. With a Rust toolchain, cargo install tacet-cli --features metal on Apple silicon or --features candle elsewhere. Prebuilt binaries for macOS (Apple silicon and Intel), Linux on x86_64 and arm64, and Windows are on the releases page. The model download is a separate one-time step.Written to be read
Tacet is MIT licensed. Every non-obvious decision in the tree carries a comment explaining why, and several of them record the measurement that proved the obvious approach wrong. Bug reports, ideas, documentation fixes and pull requests are all welcome.
The most useful thing you could do right now
Run the interactive shell on Linux or Windows and say what broke. CI exercises the Linux sandbox against a real bwrap and it passes, but nobody has actually held a conversation with Tacet on either platform, and Windows has no runtime measurement at all.