# publishwith.ai > Secure multi-tenant platform for AI agents to publish, share, and manage governed HTML, Markdown, data-backed artifacts, and live sandboxed Python reports via MCP. ## Docs - [AI Publishing Guide](https://publishwith.ai/ai-guide.html): Setup, workflows, and examples for AI agents - [Governance](https://publishwith.ai/governance.html): Controls for IT and security teams (SSO, ACL, audit, EU data residency) - [Full LLM reference](https://publishwith.ai/llms-full.txt): Complete operational manual in plain text - [User Guide](https://publishwith.ai/user-guide.html): End-user documentation - [Cookbook](https://publishwith.ai/docs/cookbook.md): Worked examples and recipes ## API - MCP endpoint: https://publishwith.ai/mcp - Protocol: Model Context Protocol (Streamable HTTP) - Auth: `Authorization: Bearer ` - Tool: `publishwithai` (single tool, action-based dispatch) - Inline docs: `action="docs", topic="api|audience|csrf|current_user|destructive|docs|dynamic|edit|errors|files|liquid|lifecycle|manifest|publish|reports|search|security|share|sql|ttl|upload|users|views|visibility"` (several at once: `topic="publish share"`). Each topic returns only its own section, a few percent of the manual. `action="docs"` with no topic returns the full ~34KB manual: last resort ## CLI - AI-first terminal CLI for agents without MCP config: a thin Bearer-auth client over the REST API - Install: `go install github.com/publishwith-ai/publishwithai-cli/cmd/publishwithai@latest` - Auth: `PUBLISHWITHAI_API_KEY` (Bearer), base `PUBLISHWITHAI_BASE_URL` (default https://publishwith.ai) - Unique capability: `publishwithai publish ./dir` reads a local folder directly instead of inlining files into JSON - Commands: `publish `, `share`, `status`, `list`, `search`, `docs`, `call --arg k=v` - Source: https://github.com/publishwith-ai/publishwithai-cli ## Actions - `create_artifact` — Create a DRAFT artifact (static or dynamic mode, optional description). Not needed to publish: `publish_static(name=...)` creates and publishes in one call - `list_artifacts` — List all artifacts in your workspace (optional query filter) - `delete_artifact` — Delete an artifact and all its data - `publish_static` — Upload HTML, Markdown, CSS, JS, images (incremental via token). Pass `name` instead of `artifact_id` to create-or-update in a single call. Optional `base_version` guards against overwriting a newer version another author published (returns `VERSION_CHANGED` + a confirm token) - `publish_dynamic` — Publish YAML manifest + Liquid templates + SQL queries. Also accepts `name` instead of `artifact_id` - `validate_artifact` — Validate a manifest before publishing - `execute_sql` — Run SQL on an artifact's isolated SQLite database - `list_tables` — List tables and columns in an artifact's database - `preview` — Fetch rendered HTML (works for static, dynamic, and markdown) - `get_source` — Fetch the RAW source files of an artifact (optional `version`) to edit then republish. Returns `{artifact_id, mode, version, files{}}` in the same shape `publish_static` accepts (text inline, binary base64). Use this — NOT the published URL or `preview` (both return rendered HTML) — as the edit source. Errors: NOT_PUBLISHED, FILE_NOT_FOUND, NOT_AUTHORIZED - `request_upload` — Get an out-of-band upload token to add binary files (images, fonts) > 64 KiB to an artifact without burning model output tokens. Returns `upload_token`, `upload_url`, `upload_expires_at` (5-minute TTL), and a ready-to-paste `curl` command. `publish_static` also returns these fields so you can upload binaries right after publishing. - `share_with` — Grant ONE principal access (tenant_user/tenant_group/external_email/audience, or `auto` to let the server pick the lane from an email or a person name, saving the `find_people` call). Additive; never changes visibility. External grants produce a token share link (shown once) and may hold `view` only. Returns result_code, resolved_lane, artifact url, visibility and the resulting access list (each entry with its grant_id), plus share_url for external grants - `set_access` — Declarative bulk access: set owners/editors/viewers/groups in one call. replace=true revokes grants not in the new set. owner_only=true resets to owner-only + private - `set_visibility` — Set artifact visibility: private (default), tenant (any member), or public (anyone, no login). Named grants are not removed when going private - `list_access` — Who CAN access: visibility, owner, and all named grants with grant_id, provenance and expiry - `list_views` — Who DID access: per-view log with viewer_email, principal_type, path, IP, timestamp - `revoke_access` — Remove a direct grant by principal or grant_id. Reports residual_access if access remains via another path - `set_published` — Toggle artifact online/offline (content kept). published=true requires version>0 - `set_ttl` — Set a time limit (ttl_days). After it, the artifact auto-goes-offline behind a wall for public visitors; owner and MCP/REST keep access. ttl_days=0 removes it. Max 365 - `create_user` — Invite a user to your workspace (paid plans) - `list_groups` — List access groups - `list_users` — List workspace users (optional query: partial match on email or display name) - `find_people` — Resolve a recipient by name or email against your org directory (real users + provisioned IdP people) to share with the right person - `list_audience_groups` — List audience groups (named sets of external contacts) for restricted-share fan-out - `set_audience_group` — Create or replace an audience group by name with a list of {display_name, email} contacts - `delete_audience_group` — Delete an audience group by id - `validate_python` — Synchronously validate a Python report script (no run); returns what is supported, what is missing, the in-sandbox alternative, and the egress connections granted to your groups (Team/Enterprise; requires tenant opt-in) - `publish_python` — Store a Python report (report.py + report.yaml) as a python-mode artifact; linted first (Team/Enterprise; requires tenant opt-in + editor role) - `run_python` — Run a stored report against its own SQLite and render a fresh version on demand; idempotent on output (Team/Enterprise; requires tenant opt-in + editor role) - `search` — Full-text content search with ranked results and snippets (Team/Enterprise) - `docs` — Fetch inline documentation ## Key Features - Static artifacts: HTML, Markdown (auto-rendered with GFM, Mermaid, KaTeX), CSS, JS, images - Dynamic artifacts: SQLite database + Liquid templates + YAML manifest routing - Live Python reports (Team/Enterprise): LLM-authored Python that queries the artifact's own SQLite and pulls approved external APIs, rendering fresh output on demand or on a schedule. Runs in a hardened per-run CPython-WASM sandbox: no raw sockets or filesystem, read-only DB by default, strict time/memory/egress limits. External APIs reached only through admin-defined named connections; the host injects the credential behind an SSRF guard and the script never sees the secret. Requires tenant opt-in. - JSON API: queries.json/mutations.json expose named SQL as REST endpoints - Share links: token-based URLs with optional TTL, recipient email notification, access levels (open or restricted), view counting - Access control: per-artifact ACL with owners/editors/viewers, user and group-based - Security: CSP, HTML sanitization, SQL parameterization, CSRF protection, audit logging - Markdown features: tables, code highlighting, Mermaid diagrams, KaTeX math, GitHub alerts, footnotes ## Liquid Template Reference Templates use Shopify Liquid syntax. Available context: - Query results: `{% for row in items %}{{ row.name }}{% endfor %}` - User context: `{{ user.email }}`, `{{ user.display_name }}`, `{{ user.role }}`, `{{ user.groups }}` - CSRF: `{{ csrf_token }}` (required in POST forms) - SQL params: `:current_user`, `:current_user_role`, `:current_user_name` - Filters: upcase, downcase, capitalize, size, first, last, sort, where, map, join, split, replace, strip, truncate, escape, url_encode, default, round, date - Tags: for, if/elsif/else, unless, assign, capture, comment - Docs: https://shopify.github.io/liquid/