Wiki Guide
Kanbus wiki pages are Markdown files with Jinja2-style templates. Rendering is a two-stage pipeline:
- Jinja first — evaluate the template against the live issue index (queries, counts, references,
ai_summarize, and related helpers). - Markus second — convert the Jinja-resolved Markdown with Markus (
anthus-markus/markusmd.convert) into semantic HTML. Markus extends GitHub Flavored Markdown with colon-fenced directives such aspull-quote,card-grid, andtwo-up. Unknown directives fail validation.
The console wiki preview consumes backend-rendered HTML that already includes Markus semantic classes (for example markus-pull-quote, markus-card-grid). The browser applies console styling only; it does not parse :::directives client-side.
Markus renderer (not PyPI markus)
Do not run pip install markus. The PyPI package markus is Mozilla's metrics library (Datadog, StatsD, and similar backends). It has nothing to do with Kanbus wiki rendering.
Kanbus wiki HTML uses Markus — Anthus-Flavored Markdown with colon-fenced :::directives such as pull-quote and card-grid. The correct Python distribution is anthus-markus (import markusmd, entry point markusmd.convert). It is pinned in python/pyproject.toml and installed automatically when you run pip install -e python from this repository.
| Toolchain | Markus dependency | Install notes |
|---|---|---|
kbs (Rust release binary) |
Built-in wiki_markus module |
No separate Markus package; build with cargo build --release |
kanbus (Python CLI) |
anthus-markus (PyPI, >=0.5.1,<0.6) |
Pulled in by pip install -e python; do not substitute PyPI markus |
| Papyrus / newsroom pods | Same as Kanbus | Use kbs wiki render from the pod checkout; no ElevenLabs or site build required |
To smoke-test Markus HTML rendering from the repository root (no console server, no ElevenLabs, no full site build):
kbs wiki render project/wiki/index.md --html | grep markus-document
To verify a directive converts to semantic HTML:
kbs wiki render project/wiki/index.md --json
The JSON payload includes rendered (post-Jinja Markdown) and rendered_html (Markus HTML). Warnings stay on stderr.
If you need the Markus library outside Kanbus (for example, to experiment in a Python REPL):
pip install "anthus-markus>=0.5.1,<0.6"
python -c "from markusmd import convert; print(convert('# Hello', include_css=False, full_document=False))"
Never install the unrelated PyPI markus package for wiki work.
Where wiki pages live
Wiki pages live in project/wiki/. Use kanbus wiki render <page> to render a page and print the result to stdout.
Console wiki workspace
- Access: open the console and switch the top view toggle to “Wiki” (main panel, not a sidebar). Board and Metrics remain available in the same toggle.
- Create: click
New, enter a relative.mdpath (no leading slash or..). The page is saved immediately with starter content. - Edit: type in the editor;
Savewrites toproject/wiki/<path>. Unsaved changes block page or panel switches unless you confirm. - Preview: click
Renderto render the current draft on the backend; errors appear in the wiki error banner while the last good preview remains. - Rename/Delete: use
RenameorDeleteon the selected page. Rename keeps selection on the new path; delete selects the next page or shows the empty state. - Persistence: the selected view (Board/Wiki/Metrics) survives reload. A before-unload guard warns if the wiki editor is dirty.
Jinja2 primer
{{ expr }}renders an expression{% for x in items %}loops over a list{% if condition %}controls conditional output{# comment #}is a template comment
Example:
{% if count(status="open") == 0 %}
All clear.
{% else %}
Open issues: {{ count(status="open") }}
{% endif %}
Template functions
The following functions are available in all wiki templates:
query(**filters)-> list of issuescount(**filters)-> integerissue(id)-> issue or Nonechildren(id)-> list of issuesblocked_by(id)-> list of issuesblocks(id)-> list of issues
Common filters for query and count:
type(exact match)status(exact match)priority(exact match)priority_lte/priority_gteassigneelabelparentsort(prefix with-for descending)limit
Examples
1) Basic status counts
Open: {{ count(status="open") }}
Closed: {{ count(status="closed") }}
2) List open tasks by priority
{% for issue in query(type="task", status="open", sort="priority") %}
- [{{ issue.id }}] {{ issue.title }} (P{{ issue.priority }})
{% endfor %}
3) Epic progress summary
{% set epic = issue("kanbus-epic01") %}
## {{ epic.title }}
{{ count(parent=epic.id, status="closed") }}/{{ count(parent=epic.id) }} tasks complete
4) Show blocked issues with blockers
{% for issue in query(status="blocked") %}
- [{{ issue.id }}] {{ issue.title }}
Blocked by:
{% for blocker in blocked_by(issue.id) %}
- [{{ blocker.id }}] {{ blocker.title }}
{% endfor %}
{% endfor %}
5) Issues by assignee
{% for issue in query(assignee="you@example.com", status="open") %}
- [{{ issue.id }}] {{ issue.title }}
{% endfor %}
6) High-priority work queue
{% for issue in query(status="open", priority_lte=1, sort="priority") %}
- [{{ issue.id }}] {{ issue.title }} (P{{ issue.priority }})
{% endfor %}
7) Status summary table
| Status | Count |
|--------|-------|
| Open | {{ count(status="open") }} |
| In progress | {{ count(status="in_progress") }} |
| Blocked | {{ count(status="blocked") }} |
| Closed | {{ count(status="closed") }} |
8) Single issue detail block
{% set item = issue("kanbus-a1b2c3") %}
## {{ item.title }}
Status: {{ item.status }}
Priority: {{ item.priority }}
Assignee: {{ item.assignee or "unassigned" }}
9) Show children of an epic
{% for child in children("kanbus-epic01") %}
- [{{ child.id }}] {{ child.title }} ({{ child.status }})
{% endfor %}
10) Show what an issue blocks
{% for blocked in blocks("kanbus-epic01") %}
- [{{ blocked.id }}] {{ blocked.title }}
{% endfor %}
11) Filter by label with limit
{% for issue in query(label="backend", status="open", limit=5, sort="-updated_at") %}
- [{{ issue.id }}] {{ issue.title }}
{% endfor %}
Rendering
Render a wiki page from the project root. By default, wiki render prints the post-Jinja Markdown (backward compatible with scripts and agents). Use --html to print Markus semantic HTML, or --json to receive both rendered (Markdown) and rendered_html (HTML) fields.
kanbus wiki render project/wiki/index.md
kanbus wiki render project/wiki/index.md --html
Markus layout directives are valid in wiki source after Jinja evaluation. Example pull quote:
:::pull-quote
> Measure what matters.
{: attribution="Editorial principle" }
:::
List wiki pages:
kanbus wiki list
Search wiki pages (prints 0 results when nothing matches):
kanbus wiki search <query>
Machine-readable output for agents
Use --json on wiki list, wiki search, and wiki render when a script or agent needs structured output. Human text remains the default.
kanbus wiki list --json
kanbus wiki search alpha --json
kanbus wiki render index.md --json
JSON search with zero matches returns "count": 0 and "pages": [] (not the human 0 results line). Render warnings stay on stderr.
Use --limit N on wiki list and wiki search to cap results after sorting (0 means no limit). wiki render does not support --limit.
For more CLI details, see CLI_REFERENCE.md.