Kanbus

Git-backed project management for people and AI agents.

Wiki Guide

Kanbus wiki pages are Markdown files with Jinja2-style templates. Rendering is a two-stage pipeline:

  1. Jinja first — evaluate the template against the live issue index (queries, counts, references, ai_summarize, and related helpers).
  2. 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 as pull-quote, card-grid, and two-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

Jinja2 primer

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:

Common filters for query and count:

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.