# bDS User Guide ## In this article - [Who this guide is for](#who-this-guide-is-for) - [How bDS works](#how-bds-works) - [Getting started](#getting-started) - [Understanding the interface](#understanding-the-interface) - [Working with posts](#working-with-posts) - [Working with pages](#working-with-pages) - [Working with media](#working-with-media) - [Using macros](#using-macros) - [Using scripting](#using-scripting) - [Using the AI assistant](#using-the-ai-assistant) - [Organizing with tags](#organizing-with-tags) - [Importing from WordPress (WXR)](#importing-from-wordpress-wxr) - [Using Git (Source Control)](#using-git-source-control) - [Configuring settings](#configuring-settings) - [Publishing in bDS (current scope)](#publishing-in-bds-current-scope) - [Typical editorial workflows](#typical-editorial-workflows) - [Working fully offline](#working-fully-offline) - [Troubleshooting and recovery](#troubleshooting-and-recovery) - [Team conventions](#team-conventions) ## Who this guide is for This guide is written for people who use bDS day to day to create, edit, and manage blog content. It is intended for editors, content managers, and project owners who want clear guidance on what each part of the application does and how to use it safely. The focus is practical usage: what an element is, when it should be used, and how it fits into a reliable workflow. If you are looking for implementation details, architecture notes, or development setup, use the project README. This document stays focused on end-user operation and editorial decisions. ### Key takeaways - bDS documentation should help you make better day-to-day decisions, not just complete isolated clicks. - Each chapter explains purpose first, then usage. - Safe content handling and recoverability are central themes throughout this guide. [↑ Back to In this article](#in-this-article) --- ## How bDS works bDS is a local-first writing and publishing workspace. In practice, that means your core work does not depend on constant internet access. You can draft, revise, structure, preview, and publish content entirely on your local machine. Optional online features, such as remote Git synchronization or AI-assisted workflows, extend this model but do not replace it. Understanding three terms is important for using bDS correctly. A draft is your in-progress state and is meant for active editing. Publishing in bDS marks a local content state as published inside your project. A Git commit creates a versioned snapshot that can be recovered, shared, and synchronized. These three states are related, but they are not the same operation. The recommended sequence is simple: edit in draft, publish when the content is ready, and then commit immediately. This sequence is the safest way to protect work, collaborate with others, and keep project history understandable over time. ### Key takeaways - bDS is designed for local reliability first. - Publish and commit are different actions and both matter. - The default safe lifecycle is: Draft → Publish → Commit. [↑ Back to In this article](#in-this-article) --- ## Getting started Before beginning editorial work, confirm that your project context is set correctly. Start by opening bDS and selecting the correct project. If this is a new project, create it and define its identity early, including project name and description. This helps keep exports, metadata, and team workflows aligned from the beginning. Next, open Settings and verify the project data path. The data path determines where content and related files are stored, so it should reflect your backup strategy and how your team expects to work. You should also set the Public Base URL as soon as possible, because sitemap generation depends on it. Finally, define language and author defaults. These defaults reduce repetitive editing work and keep output consistent across content created by multiple contributors. ### Key takeaways - Set identity, data location, and Public Base URL at the beginning. - Configure language and author defaults before regular editing starts. - Early setup decisions reduce cleanup work later. [↑ Back to In this article](#in-this-article) --- ## Understanding the interface The bDS interface is organized to support content workflows rather than isolated forms. The Activity Bar on the left is your primary navigation between major areas such as Posts, Pages, Media, Tags, Import, Source Control, and Settings. The Sidebar changes based on the active area and helps with filtering, selection, and navigation. The Editor area is where most work happens and supports tabbed editing for content, configuration, and analysis views. The bottom panel and status area are especially important during long operations such as imports, rebuild actions, or larger media tasks. They provide progress and completion feedback so you can verify that a task finished correctly. Toast messages provide short success or error confirmation and should be treated as quick status signals, not detailed logs. Tab behavior is optimized for quick scanning and focused editing. Single-clicking often opens a transient tab, while double-clicking pins a tab for ongoing work. This pattern lets you inspect many items quickly while keeping active tasks stable. ### Key takeaways - Use the Activity Bar for section-level context switching. - Use the Sidebar for finding and narrowing content. - Pin tabs when you are doing deeper editing work. [↑ Back to In this article](#in-this-article) --- ## Working with posts The Posts section is intended for chronological content such as articles, notes, and recurring updates. Choose Posts when publication timing, archive behavior, and regular update cycles are part of your content strategy. In most editorial teams, Posts represent the primary stream of outward-facing content. A post usually combines several layers of information: title, body content, category, tags, and status. The title establishes the main topic. The body carries the full narrative or note. Categories provide broad structural grouping, while tags support more specific discovery and filtering. Status indicates lifecycle stage and should be used intentionally to avoid ambiguity in collaborative workflows. A reliable post workflow starts by drafting content to completion, then reviewing structure and metadata, and finally previewing the output before publishing. After publishing, commit in Source Control immediately so the editorially approved state is recoverable and shareable. ### Key takeaways - Use Posts for date-oriented, regularly updated content. - Treat category and tags as distinct tools: broad grouping versus precise discovery. - Publish only when editorially ready, then commit right away. [↑ Back to In this article](#in-this-article) --- ## Working with pages Pages are for durable, non-chronological content such as About, Contact, legal notices, and other structural information. Use Pages when content should remain stable in navigation and should not be interpreted as part of a time-based feed. Because pages are often revisited over long periods, naming consistency matters. Keep titles and slugs predictable, and avoid unnecessary structural churn. If your project has navigation conventions, apply them consistently so contributors can find and update page content without guesswork. The working pattern is similar to posts—draft, review, preview, publish, commit—but editorial intent is different. With pages, the emphasis is on clarity and long-term maintainability rather than release cadence. ### Key takeaways - Use Pages for stable, structural content. - Keep titles and slugs consistent for long-term maintainability. - Apply the same safe lifecycle: Draft → Publish → Commit. [↑ Back to In this article](#in-this-article) --- ## Working with media The Media section is where you import, describe, and maintain assets used by posts and pages. It is not only a file list; it is also the place where accessibility and content quality are reinforced through metadata. In day-to-day work, media quality often determines whether published content feels complete and professional. When importing media, add metadata immediately while context is still fresh. Alt text should describe image meaning for accessibility, captions should support reader understanding, and media tags should help with retrieval and reuse. The goal is to make media usable both now and later, including by teammates who did not import the asset. After placing media in content, run a quick preview pass to confirm placement and context. When possible, commit post changes and their related media changes together. This keeps history coherent and makes future rollback or investigation much easier. ### Key takeaways - Media management includes metadata quality, not only file import. - Add alt text and captions during import, not as a postponed task. - Commit content and related media in the same change when possible. [↑ Back to In this article](#in-this-article) --- ## Using macros Macros let you insert dynamic content blocks directly inside post/page Markdown by using `[[macro_name ...]]` syntax. bDS expands these macros during preview and generated output using local assets only. Use macros when you need reusable rich blocks (for example embedded videos, media galleries, archive grids, or computed tag clouds) without writing raw HTML. ### YouTube macro Use `[[youtube id="VIDEO_ID" title="Optional title"]]` when you want to embed a YouTube clip directly in a post or page. This macro is best for video references, walkthroughs, and embedded talks that should stay in the editorial flow instead of linking out to another tab. The `id` parameter is required and should contain the YouTube video ID. The `title` parameter is optional, but recommended for accessibility because it becomes the reader-facing label for the embedded frame. ### Vimeo macro Use `[[vimeo id="VIDEO_ID" title="Optional title"]]` for Vimeo-hosted video content. It behaves similarly to the YouTube macro, but targets Vimeo as the video source. As with YouTube, `id` is required and `title` is optional. Use `title` whenever possible so screen-reader and assistive-technology users receive useful context. ### Gallery macro Use `[[gallery columns="3" caption="Optional caption"]]` to render a lightbox-enabled media gallery from assets linked to the current post. This macro is appropriate when several related images belong together and should be browsed as one visual group. The `columns` parameter controls layout density and accepts values from `1` to `6` (default is `3`). The optional `caption` parameter adds context above or below the gallery depending on theme presentation. ### Photo archive macro Use `[[photo_archive year="2025" month="2"]]` when you want an archive-style grid based on media dates. This is useful for timeline-oriented projects where readers should navigate image collections by month or year. Both `year` and `month` are optional. If `year` is omitted, bDS shows recent months. If `year` is provided without `month`, bDS presents the year scope. The legacy alias `[[photo_album ...]]` is still supported for compatibility. ### Tag cloud macro Use `[[tag_cloud orientation="mixed_diagonal" width="900" height="420"]]` to visualize published tag usage as a weighted cloud. This macro is best for discovery pages, thematic overviews, and archive entry points where content density matters. Word size scales with usage counts. Colors are theme-aware and distributed by quantity quantiles using eased interpolation so high-volume datasets stay readable. The color progression remains least-to-most (blue → green → yellow → orange → red), and clicking a word opens that tag archive route. The optional `orientation` parameter supports `horizontal`, `mixed_hv`, and `mixed_diagonal`. The optional `width` and `height` parameters control canvas size and default to `900` and `420`. ### Key takeaways - Macros are inserted directly in Markdown and expanded during preview/publish rendering. - Use macro parameters to control behavior without leaving the editor. - `tag_cloud` is data-driven and links directly into tag archive navigation. [↑ Back to In this article](#in-this-article) --- ## Using scripting Scripts are Python files stored in your project's `scripts/` directory. Each file carries embedded YAML frontmatter in a docstring block at the top, which bDS uses to index the script in its database. This keeps scripts portable, Git-reviewable, and consistently tracked without a separate configuration file. Each script has a **Kind** (macro, transform, or utility) and an **Entrypoint** that names the Python function to invoke. bDS inspects your script to list all top-level function names so you can choose which one to call. Keep scripts versioned through your normal Git workflow, review changes carefully, and prefer small, focused scripts. ### Transform scripts Transform scripts run during blogmark import to modify incoming content before bDS creates the post. The entrypoint function receives a mutable `post` dict and must return it. ```python def normalize_blogmark(post): # 1) Manipulate title title = (post.get("title") or "").strip() if title and not title.startswith("[Clipped]"): post["title"] = f"[Clipped] {title}" # 2) Manipulate text/content content = (post.get("content") or "").strip() prefix = "Imported from blogmark\n\n" if content and not content.startswith(prefix): post["content"] = prefix + content # 3) Set or replace categories post["categories"] = ["Inbox", "Research"] # 4) Add and normalize tags tags = post.get("tags") or [] tags.append("blogmark") tags.append("clipped") post["tags"] = sorted({str(tag).strip().lower() for tag in tags if str(tag).strip()}) # 5) Optional user notification toast(f"Transform applied: {post.get('title')}") return post ``` You can also accept an optional `context` argument that bDS passes when importing a blogmark: ```python def normalize_blogmark(post, context=None): url = (context or {}).get("url", "") toast(f"Transform applied from: {url}") return post ``` `context` contains `source` (always `"blogmark"`) and `url` (the original bookmarked URL). Notes: - `title` and `content` are strings. - `categories` and `tags` are string lists (e.g., `['News', 'AI']`). - Return the mutated `post` dict from your transform function. - `toast(message)` is a built-in available in transform scripts to send user-facing notifications. - When a transform fails, bDS automatically surfaces an error toast and writes diagnostics to the Output panel. - Keep transforms small and deterministic, especially when multiple active transforms run in sequence. ### Macro scripts Macro scripts let you create custom `[[macro_name ...]]` blocks that expand during preview and page generation. Create a script with kind set to **macro** and pick a slug — the slug becomes the macro name used in Markdown. The entrypoint function always receives two arguments: ```python def render(context, post): params = context.get("params") or {} # key-value pairs from [[slug key="value"]] env = context.get("env") or {} language = env.get("mainLanguage", "en") # project render language (generation only) is_preview = env.get("isPreview", False) # True when rendering in the editor preview title = (post or {}).get("title", "Unknown") custom_label = params.get("label", "") return {"html": f"
{title}: {custom_label} ({language})
"} ``` `context` is a dict with two keys: - `params` — a dict of all key-value attributes from the macro tag. For example, `[[my_macro title="Hello"]]` gives `context["params"]["title"] == "Hello"`. - `env` — a dict containing `isPreview` (bool). During generation it also includes `mainLanguage` (the project's render language code) and `hook` (the macro slug as written in Markdown). `post` is the full PostData dict for the post containing the macro, or `None` when post data is unavailable. The function must return a dict with an `html` key containing the rendered HTML string. #### Using the application API in macros Macro scripts can call the application API through the `bds_api` module. Because API calls are asynchronous, the entrypoint must be an `async def`: ```python from bds_api import bds async def render(context, post): tags = await bds.posts.get_tags() items = "".join(f"