feat(writes): enable write actions by default (opt-out)
Invert the global write toggle so writes are ENABLED by default and the user opts OUT, while keeping all other safety intact (per-call confirm=true dry-run preview and the on-disk audit log are unchanged). - writes.py: use a `writes_disabled` flag file instead of `writes_enabled`; `writes_enabled()` returns True unless the flag exists (env var still honored either way); `set_writes(False)` creates the flag, `set_writes(True)` removes it. Update user-facing notes. - tests: default is now ENABLED; adjust toggle/disabled tests (set disabled explicitly via set_writes(False) or FAMILIAR_ENABLE_WRITES=0). - README.md / CLAUDE.md: document writes are on by default, opt out via `familiar writes disable`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
6 files changed
+36
-23
No files matched your search
@@ -19,7 +19,7 @@ uv run ruff check . # lint (run both before committing; CI enforces th
|
||||
uv run familiar # run the MCP server over stdio (how Claude launches it)
|
||||
uv run familiar login # browser EVE SSO login (adds a character; run once per character)
|
||||
uv run familiar status # list logged-in characters
|
||||
uv run familiar writes enable # allow write actions (default: disabled)
|
||||
uv run familiar writes disable # block write actions (default: enabled)
|
||||
```
|
||||
|
||||
There is no separate build step; `uv build` produces the wheel (CI does this on merge).
|
||||
@@ -34,7 +34,7 @@ There is no separate build step; `uv build` produces the wheel (CI does this on
|
||||
|
||||
**Per-character / per-corp pattern.** [charutil.py](src/familiar/charutil.py) is the backbone of every authenticated tool. `run_per_character(character, fetch)` runs a fetcher for one named character or **all** logged-in ones (when `character` is None), returning a uniform `{"characters": [...]}`. `run_per_corp` additionally resolves each character's `corporation_id` (corp endpoints need the right corp role or ESI 403s). `one_token` picks a single token for thing-scoped lookups (e.g. a structure). `summarize(items, limit)` gives `{count, sample}`. account.py and all read modules build on these.
|
||||
|
||||
**Write safety — the choke point.** [writes.py](src/familiar/writes.py) `guard(action, params, confirm, execute)` is the single gate every mutating tool calls. `confirm=False` → dry-run preview (nothing happens); `confirm=True` but writes disabled → `WriteDisabled`; `confirm=True` + enabled → execute + append to an audit log. Writes are **off by default** (toggle via `familiar writes enable` / `FAMILIAR_ENABLE_WRITES`). Write tools take a *required* `character` and a `confirm` flag; reads take an *optional* `character`. When adding a write tool, route it through `writes.guard` — never call a mutating ESI endpoint directly.
|
||||
**Write safety — the choke point.** [writes.py](src/familiar/writes.py) `guard(action, params, confirm, execute)` is the single gate every mutating tool calls. `confirm=False` → dry-run preview (nothing happens); `confirm=True` but writes disabled → `WriteDisabled`; `confirm=True` + enabled → execute + append to an audit log. Writes are **on by default** (opt out via `familiar writes disable`; toggle via `familiar writes enable`/`disable` or `FAMILIAR_ENABLE_WRITES`). Write tools take a *required* `character` and a `confirm` flag; reads take an *optional* `character`. When adding a write tool, route it through `writes.guard` — never call a mutating ESI endpoint directly.
|
||||
|
||||
## Testing conventions
|
||||
|
||||
|
||||
Reference in new issue
Block a user