# 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](https://anthusai.github.io/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`](https://pypi.org/project/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](https://anthusai.github.io/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):

```bash
kbs wiki render project/wiki/index.md --html | grep markus-document
```

To verify a directive converts to semantic HTML:

```bash
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):

```bash
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 `.md` path (no leading slash or `..`). The page is saved immediately with starter content.
- Edit: type in the editor; `Save` writes to `project/wiki/<path>`. Unsaved changes block page or panel switches unless you confirm.
- Preview: click `Render` to render the current draft on the backend; errors appear in the wiki error banner while the last good preview remains.
- Rename/Delete: use `Rename` or `Delete` on 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:

```markdown
{% 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 issues
- `count(**filters)` -> integer
- `issue(id)` -> issue or None
- `children(id)` -> list of issues
- `blocked_by(id)` -> list of issues
- `blocks(id)` -> list of issues

Common filters for `query` and `count`:

- `type` (exact match)
- `status` (exact match)
- `priority` (exact match)
- `priority_lte` / `priority_gte`
- `assignee`
- `label`
- `parent`
- `sort` (prefix with `-` for descending)
- `limit`

## Examples

### 1) Basic status counts

```markdown
Open: {{ count(status="open") }}
Closed: {{ count(status="closed") }}
```

### 2) List open tasks by priority

```markdown
{% for issue in query(type="task", status="open", sort="priority") %}
- [{{ issue.id }}] {{ issue.title }} (P{{ issue.priority }})
{% endfor %}
```

### 3) Epic progress summary

```markdown
{% 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

```markdown
{% 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

```markdown
{% for issue in query(assignee="you@example.com", status="open") %}
- [{{ issue.id }}] {{ issue.title }}
{% endfor %}
```

### 6) High-priority work queue

```markdown
{% for issue in query(status="open", priority_lte=1, sort="priority") %}
- [{{ issue.id }}] {{ issue.title }} (P{{ issue.priority }})
{% endfor %}
```

### 7) Status summary table

```markdown
| 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

```markdown
{% set item = issue("kanbus-a1b2c3") %}
## {{ item.title }}
Status: {{ item.status }}
Priority: {{ item.priority }}
Assignee: {{ item.assignee or "unassigned" }}
```

### 9) Show children of an epic

```markdown
{% for child in children("kanbus-epic01") %}
- [{{ child.id }}] {{ child.title }} ({{ child.status }})
{% endfor %}
```

### 10) Show what an issue blocks

```markdown
{% for blocked in blocks("kanbus-epic01") %}
- [{{ blocked.id }}] {{ blocked.title }}
{% endfor %}
```

### 11) Filter by label with limit

```markdown
{% 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.

```bash
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:

```markdown
:::pull-quote
> Measure what matters.
{: attribution="Editorial principle" }
:::
```

List wiki pages:

```bash
kanbus wiki list
```

Search wiki pages (prints `0 results` when nothing matches):

```bash
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.

```bash
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](cli-reference.html).
