Skip to content

Privacy & security

WRITING AGENT runs locally, operated by you on your own machine. A few properties are worth understanding before you point it at the web or publish what it writes.

The only outbound network calls are:

  • OpenRouter - your configured endpoint, for every LLM call.
  • DuckDuckGo - the default researcher (on by default), for search snippets.
  • Firecrawl - only if you set search_provider: firecrawl (needs FIRECRAWL_API_KEY), for search + page scraping.
  • Full page fetches - only when deep_research is enabled.
  • Wikimedia Commons - optional image search when use_images is on.

All manuscript data stays on disk locally. Telemetry stays local - per-call usage records (model, tokens, cost, latency) are written only to .index/telemetry/; nothing is sent anywhere.

writing-agent web serves the browser dashboard from a local server that binds 127.0.0.1 only, with no authentication - the same trust boundary as the TUI on the same machine. It never listens on a network interface, so treat it as a single-operator tool and do not port-forward or reverse-proxy it onto a network.

The seo and promote commands (and auto_promote) only ever write local files - an seo_report.md, a keywords.json, and promo/*.md drafts, plus optimizing the manuscript’s H1 title for the keyword. They do not post, schedule, or transmit anything to any social network, CMS, or third-party service; publishing is always a manual step you take yourself.

Your model-host API key (e.g. OPENROUTER_API_KEY) lives in .env (gitignored) and is read only to call that host. Never commit it.

The TUI’s conversational assistant can propose commands and run them automatically - but this is fenced in code, not by prompt:

  • Destructive/account commands (delete, write, /user) are blocked from auto-execution; you must type them yourself. (Settings - /set - can be changed from plain English, since they’re reversible and non-destructive.)
  • Creating a project requires your explicit typed go-ahead (“go ahead”, “run it”) - the shell verifies your own message was a confirmation before executing a chat-emitted new.
  • Project/user ids are validated and deletes are confined to the brain directory.

Everything fetched from the public web - search snippets and deep-research page text - is fenced as data-only before entering any prompt: spoof-resistant markers (markers faked inside the content are neutralized) plus a standing instruction that the block is never instructions. A hostile page can’t direct the writer - but no fence is perfect, so review research-grounded output before publishing.

Every uncached deep-research fetch passes three checks:

  • SSRF guard - the host must resolve to globally-routable addresses only (loopback, private ranges, link-local, and cloud-metadata IPs blocked); every redirect hop is re-validated.
  • robots.txt - honored per host (WRITINGAGENT_IGNORE_ROBOTS=1 opts out).
  • Politeness - requests to the same host are spaced ≥ 1 second apart.

Manuscripts and SVG diagrams come from an LLM. Exported HTML is sanitized (scripts, iframes, and event handlers stripped), but treat any generated output as untrusted if you publish it.

max_run_tokens caps a run’s total token spend; the run pauses cleanly at the cap and is resumable. See Cost & performance and Production guards.

Please report security issues privately via GitHub’s private vulnerability reporting (Security → Report a vulnerability) rather than opening a public issue. Include reproduction steps and the affected version/commit. This is pre-1.0 software; security fixes land on master and in the latest release.