Skip to main content
## Episode 4 — Sync and publish You've written a content item and linted it clean. It still lives only on your disk. This episode closes the loop: getting it onto a live site — and being deliberate about the one step where "private" becomes "public to the world." ### `sync`: files into the database Your markdown tree is the source of truth, but a website doesn't read markdown directly — it reads a database. `sync` is the bridge: ```sh silan sync ``` `sync` parses the whole content tree, validates it, diffs it against what's already in the database, and writes the changes. It's the engine's core verb. Run it after every batch of edits. If `lint` was clean, `sync` will be too — `sync` validates again before it writes anything, so a broken tree never reaches the database. Two things to internalize: - **`sync` is safe to run repeatedly.** It diffs; it doesn't blindly rewrite. Run it as often as you like. - **`sync` does not publish.** It moves *all* your content into the database, drafts and private items included. The database is the engine's full picture. What the *public* sees is a separate decision — the next section. ### The publish gate: `visibility` Here's the most important paragraph of the whole series. The thing that decides whether an item appears on your live site is **one field**: `visibility`. Set it to `public` and the item is eligible to be served. Leave it `private` or `unlisted` and the public site will never show it — no matter what its `status` says, no matter that it's in the database. So publishing a post is, deliberately, a one-line edit you make by hand: ```yaml visibility: public ``` Change that, run `silan sync`, and the item crosses over. That's the gate. It is intentionally a manual, conscious act — the system will never flip it for you. Nothing you write goes public by accident; it goes public because you typed `public` and meant it. A useful habit: ```sh silan status ``` `status` shows you the breakdown — what's public, what's private, what's unsynced. Run it before a deploy and you see exactly what the world is about to get. No surprises. ### Serving the site: backend and frontend The database is populated; now something has to serve it. silan-viking ships two pieces: - a **Go backend** that exposes the public content as an API, and - a **React frontend** that renders it into the actual website. For local development you run both and point a browser at the frontend — you see your site exactly as visitors will, public items only. For a real deployment, the whole stack — engine, backend, frontend, database — packages and runs through Docker end to end. One environment, reproducible, the same locally and in production. The exact run commands live in the project's own docs and the `silan-blog` workflow; the shape to remember is: **build backend, build frontend, point them at the synced database, ship the container.** ### A note on writing with an agent silan-viking has an MCP server, so an AI agent can help you author. An agent can `capture` a loose thought, `propose` a change to a content item, and `recall` earlier context. But — and this is by design — **an agent physically cannot publish or deploy.** It can draft into a proposal; it cannot flip `visibility`, cannot run a deploy. `propose`, `accept`, publish, deploy are owner-only actions. The agent writes; you decide. That boundary is a wall, not a politeness — the same instinct behind the `visibility` gate, applied to your tools. ### The whole loop, one more time ``` silan new → scaffold a correct item write prose → edit en.md silan lint → catch errors early silan sync → files into the database set visibility → the deliberate publish gate (by hand) silan sync → the change crosses over build & deploy → backend + frontend serve the public subset ``` That's the entire system. You write plain text, the engine carries it, and a single honest field stands between a private draft and the whole internet. Thanks for following the series. Now go write something — and publish it only when *you* decide it's ready.