Addons
Everything with reach beyond the working directory is an addon, and every addon is off until you install it. Not disabled: absent.
Managing them
tacet addon list # what exists, and what is installed
tacet addon install shell # asks before it writes anything
tacet addon try shell # call it once by hand
tacet addon close shell # keep the config, take the tool away
tacet addon open shell # put it back
tacet addon remove shell # forget the config tooA closed addon's tools are not in the catalog the model is shown, so it cannot call them, mention them, or fail at them.
What each one opens
| Addon | Tools | Where the line is |
|---|---|---|
| web-search | web_search, web_fetch | Your own SearXNG, running locally under Docker or at an address you already have |
| shell | shell | Only the programs you list, and no shell interpretation |
| workspace | none | Named directories the file tools may also reach |
| http | http | Only the exact hosts you list, HTTPS only, no redirects |
| db | db, and db_write only if you name a file | Read-only SQLite by default, through the sqlite3 binary already on your machine |
| clipboard | clipboard | Reads and writes the system clipboard |
There is no shell in the shell addon
The command runs as a program plus a list of arguments and never through sh -c, so ; rm -rf / arrives as an argument and nothing parses it. The allow list is not checked after the fact either: it is the argument's schema, so the constrained decoder cannot generate a program name outside it.
curl is network access. git can push. That is why shell sits behind the same approval question as web_search and http: once a turn has touched personal data, every call that could carry it off the machine stops and asks you first.
Writing to a database is a second tool, not a flag
db is read only and stays read only. Its lock is sqlite3 -readonly, measured against your own binary before the tool is built. If you want a database changed you name the file while installing the addon, and a separate db_write tool appears. Name nothing and it does not exist, which is the only gate that holds here: the SQL is free text, so a model that has the tool can always spell DROP TABLE.
Every db_write call is measured before it happens. The statement runs first against a copy of the file, and what you are shown is the difference that copy actually took: objects created, dropped or redefined, row counts moved, journal mode changed. Then it asks. Nothing is written until you say yes, the measured copy is left beside the database as <name>.tacet-backup, and the question is asked again for the next statement, so a no is about one statement rather than the session.
It is not one statement: sqlite3 re-parses the string it is given, so SELECT 1; DROP TABLE t runs both halves. That was measured, and it is why the effect is shown rather than the statement filtered. And allowing a file allows everything SQL can do to that file. What does hold is the file boundary: -safe refuses ATTACH, VACUUM INTO and writefile(), all three checked at startup, so the statement cannot reach a second file.
Web search points at your own server
There is no default provider and no shared endpoint. The web-search addon wants a SearXNG root you control, either a local one under Docker or one you already run. TACET_SEARXNG sets it for a single session. Requests that resolve to a private or loopback address are refused at the socket boundary, so a search result cannot be used to reach something on your own network.
Third-party tools plug in elsewhere
Addons are the fixed set above. A tool somebody else wrote joins through an MCP connection instead, and passes the same four gates as a built-in one.