home | imprint | privacy

present documentation

work with tech

sabeiro

2026-09-07 Mon 00:00

Created: 2026-10-15 Thu 16:58

documentation present

The documentation is made with mardown and .org files. We need to convert those files into a public documentation. For portfolio creation look at . First of all we need to include the header template in every file with the command [C-t h] which reads header_org.org header org .

.org files are really versatile and can export to many other formats.

pdf
using LaTeX or postscript
html
with different exporting options
html reveal
mainly using reveal.js with reveal_custom.css
html slides
my custom scripts slide.js and slide.css

This file will be outputted as blog post or slides. The main index is spiega tech.

org-files

We extensively use org files org files features to create the content which gets exported in many different media formats. We created to ease complex processing of org files like use LLMs to update tags and descriptions in the metadata.

create animations

authors:
  - admin
projects: [project]
categories: [tags]
featured: false
commentable: true
image:
  caption:
  focal_point: 'center'

Blender has its own scripting tab but it doesn’t fit in my workflow where I use python REPL and LLMs to test the commands. Blender has an addon called blender-mcp which allows to access blender methods from outside.

connect blender-mcp

So I need to run the mcp server with transport http:

cd ~/lav/src/blender_twin/deploy/mcp_client/
#bash ./blender_local_client.sh &
cd $HOME/lav/src/blender_twin/deploy/mcp_client/blender_mcp_example_code/mcp/blmcp/ 
#python3 -m blmcp
uv --directory $HOME/lav/src/blender_twin/deploy/mcp_client/blender_mcp_example_code/mcp run blender-mcp --transport http --port 9191 &

I then need a container as defined in docker_compose.yml to create a bridge between the host and the containers within docker network.

blender-mcp-bridge:
  image: alpine/socat:latest
  container_name: blender-mcp-bridge
  network_mode: "host"
  command: TCP-LISTEN:19191,fork,reuseaddr TCP:127.0.0.1:9191
  restart: unless-stopped

create animations

I can then work on a script create_animation.py or let an LLM test the blender code without exiting the container.

Mermaid produces svg files which are loaded in blender apart from text which is not recognized. For that we created a script text2svg.py to load each text tag, load a font and create a path around that text. We apply as well some grouping logic so the import in blender is smoother.

cd ~/lav/src/spiega/script/
python3 text2svg.py ~/lav/siti/f/f_twin/arch_diagram.svg
mv output.svg ~/VideoProd/in_prog/graph/arch_dia.svg
File processed: /home/sabeiro/lav/siti/f/f_twin/arch_diagram.svgresults in output.svg

video

slideshow

Create a slideshow from folders of images galery_show.py.

python3 ~/lav/src/malastro/media/galery_show.py

animation js

We can do motion graphics using javascript demos

# npx -y skills@latest add remotion-dev/skills -g -y
#pnpm i @remotion/player@4.0.535
cd ~/lav/src/spiega/knowledge
pnpm create video --yes --blank js_anim
cd js_animation
pnpm approve-builds
#npx remotion skills add
pnpm run dev
Welcome to Remotion!
[?25l? Choose a template: › - Use arrow-keys. Return to submit.
❯   Blank Nothing except an empty canvas 
    Hello World A playground with a simple animation 
    Next.js SaaS template for video generation apps 
    Next.js (Vercel Sandbox) Render videos on-demand using Vercel Sandbox 
    Recorder A video production tool built entirely in JavaScript 
    Prompt to Motion Graphics SaaS Starter Kit SaaS template for AI-powered animation generation 
    Render Server An Express.js server for rendering videos with Remotion 
    Electron Render Remotion videos from a desktop app 
    React Router SaaS template for video generation apps 
    React Three Fiber Remotion + React Three Fiber Starter Template 
    Still images Dynamic PNG/JPEG template with built-in server 
    Audiogram Text and waveform visualization for podcasts 
    Music Visualization Text and waveform visualization for podcasts 
    Prompt to Video Create a story with images and voiceover from a prompt 
    Skia React Native Skia starter 
    Overlay Overlays for video editing software 
    Code Hike Beautiful code animations 
    Stargazer Celebrate your repo stars with a video 
    TikTok Generate animated word-by-word captions 
    Editor Starter (Paid) A boilerplate for starting a video editor 

We can then batch render the video

npx remotion render <composition-id> out/video.mp4 --gl=angle --concurrency=1

voice

voice over

To speed up voice over we use some tools like

cd ~/VideoProd/in_prog/graph/
#pip install auto-editor
auto-editor 
mv output.svg ~/VideoProd/in_prog/graph/arch_dia.svg

transcribe speech

cd ~/VideoProd/clip
python ~/lav/src/kotoba/kotoba/transcribe_video.py /home/sabeiro/VideoProd/publicati/org_creator.mp4

Processing 1 video(s)...

============================================================

Processing file 1 of 1: org_creator.mp4
------------------------------------------------------------
Loading Whisper model 'base'...
Model loaded successfully.
Extracting audio from 'org_creator.mp4'...
Audio extracted successfully.
Transcribing audio with Whisper...
Detected language: Italian
Transcription completed.
Generating SRT file: org_creator.srt
Generating text file: org_creator.txt

✓ Successfully transcribed 'org_creator.mp4'
  Output files:
    - /home/sabeiro/VideoProd/publicati/org_creator.srt
    - /home/sabeiro/VideoProd/publicati/org_creator.txt

============================================================
SUMMARY
============================================================
Total videos: 1
Successful: 1
Failed: 0

exporting

We started with many tools and we tried to minimize the dependencies so over time I removed the dependencies from tools like `markdown` and `pandoc`. I rather use my own header and footer templates In emacs.el we define most of the configurations and load the libraries. In reveal_config.org we have the additional configurations for export.

conversion scripts

Each website uses different scripts

spiega
technical blog
viudi
music website
blender_twin
project docs
foto
photography website
viaggi
travel website
scritti
personal blog

Where I built custom lisp and python files for tag manipulations.

export options

We can visualize the current export options with:

[C-c C-e t]

#+TITLE:       the title to be shown (default is the buffer name)
#+AUTHOR:      the author (default taken from user-full-name)
#+DATE:        a date, an Org timestamp120, or a format string for format-time-string
#+EMAIL:       his/her email address (default from user-mail-address)
#+DESCRIPTION: the page description, e.g. for the XHTML meta tag
#+KEYWORDS:    the page keywords, e.g. for the XHTML meta tag
#+LANGUAGE:    language for HTML, e.g. ‘en’ (org-export-default-language)
#+TEXT:        Some descriptive text to be inserted at the beginning.
#+TEXT:        Several lines may be given.
#+OPTIONS:     H:2 num:t toc:t \n:nil @:t ::t |:t ^:t f:t TeX:t ...
#+BIND:        lisp-var lisp-val, e.g.: org-export-latex-low-levels itemize
               You need to confirm using these, or configure org-export-allow-BIND
#+LINK_UP:     the ``up'' link of an exported page
#+LINK_HOME:   the ``home'' link of an exported page
#+LATEX_HEADER: extra line(s) for the LaTeX header, like \usepackage{xyz}
#+EXPORT_SELECT_TAGS:   Tags that select a tree for export
#+EXPORT_EXCLUDE_TAGS:  Tags that exclude a tree from export
#+XSLT:        the XSLT stylesheet used by DocBook exporter to generate FO file

The options we have are:

H:         set the number of headline levels for export
num:       turn on/off section-numbers
toc:       turn on/off table of contents, or set level limit (integer)
\n:        turn on/off line-break-preservation (DOES NOT WORK)
@:         turn on/off quoted HTML tags
::         turn on/off fixed-width sections
|:         turn on/off tables
^:         turn on/off TeX-like syntax for sub- and superscripts.  If
you write "^:{}", a_{b} will be interpreted, but
the simple a_b will be left as it is.
-:         turn on/off conversion of special strings.
f:         turn on/off footnotes like this[1].
todo:      turn on/off inclusion of TODO keywords into exported text
tasks:     turn on/off inclusion of tasks (TODO items), can be nil to remove
all tasks, todo to remove DONE tasks, or list of kwds to keep
pri:       turn on/off priority cookies
tags:      turn on/off inclusion of tags, may also be not-in-toc
<:         turn on/off inclusion of any time/date stamps like DEADLINES
*:         turn on/off emphasized text (bold, italic, underlined)
TeX:       turn on/off simple TeX macros in plain text
LaTeX:     configure export of LaTeX fragments.  Default auto
skip:      turn on/off skipping the text before the first heading
author:    turn on/off inclusion of author name/email into exported file
email:     turn on/off inclusion of author email into exported file
creator:   turn on/off inclusion of creator info into exported file
timestamp: turn on/off inclusion creation time into exported file
d:         turn on/off inclusion of drawers

A typical syntax:

#+OPTIONS:     H:2 num:t toc:t \n:nil @:t ::t |:t ^:t f:t TeX:t ...
(org-insert-export-options-template)

export scripts

We use multiple scripts to export, convert and publish the org files into slides, blog articles and pages: org-export.

html compatibility

An exhaustive guide.

> export iframe

html css

We can add css style in the page

publish

References ref1, ref2, ref3, ref4, ref5, ref6, ref7

.org files allow the publishing option as defined in emacs.el where I can set a project and the publishing directory. All the .org files in the `base-directory` will be converted into the `publishing-directory` and the pictures will be copied.

(setq org-publish-project-alist
      `(("pages"
         :base-directory "~/lav/src/spiega/blender_twin/"
         :publishing-directory "~/lav/siti/blender_twin/a/"
         :publishing-function roam-publication-wrapper
         :recursive t
         :html-head "<link rel=\"stylesheet\" href=\"static_html//css/org.css\" type=\"text/css\"/>\n"
         )
        ("static"
         :base-directory "~/lav/src/spiega/static/blender_twin/"
         :base-extension "jpg\\|gif\\|png\\|svg\\|css\\|js"
         :recursive t
         :publishing-directory "~/lav/siti/blender_twin/"
         :publishing-function org-publish-attachment)
      ("blender_twin" :components ("pages" "static"))))
(org-publish "blender_twin" t)

In case run a webserver

cd ~/lav/siti/blender_twin
python3 -m http.server

thumbnail

Copy default thumbnail if no other is provided

cd ~/lav/siti/f/f_stage
for i in ~/lav/src/spiega/article/* ;
do
    titN1=${i%.org}
    titN=${titN1##*/}
    thumbF=thumb_$titN.png
    if [ ! -f $thumbF ]; then
        echo $titN
        cp thumb_spiega.png $thumbF
    fi
done

emacs reveal slides

Emacs has many packages to convert .org into html + reveal.js, the most common is org-reveal but I tested org-re-reveal, emacs-reveal, oer-reveal, ox-reveal and they all cause headaches.

I had to pick manually select files from reveal.js and put them in the same order in the folder reveal/ with the same relative paths.

I tend to prefer `org-reveal` which has least dependencies.

export file

I need to figure out how to change filename (add _slide) and how to move it to another directory

script

We use one command to export this file to reveal.js and move it to the final folder.

(org-reveal-export-to-html)
;;(org-re-reveal-export-to-html)
mv documentation_present.html ~/lav/siti/spiega/a/documentation_present_slide.html
#firefox http://localhost/spiega/a/documentation_present_slide.html

oer package

Here we test the oer package

(use-package oer-reveal-publish)
(oer-reveal-setup-submodules t)
(oer-reveal-generate-include-files t)
(oer-reveal-publish-setq-defaults)
(setq oer-reveal-publish-babel-languages '((dot . t) (emacs-lisp . t))
      org-publish-project-alist
      (list (list "img"
                  :base-directory "~/lav/siti/blender_twin/"
                  :base-extension "png"
                  :publishing-function 'org-publish-attachment
                  :publishing-directory "~/lav/siti/f/f_twin/")))
img :base-directory ~/lav/siti/blender_twin/ :base-extension png :publishing-function org-publish-attachment :publishing-directory ~/lav/siti/f/f_twin/

wrap in tags

(use-package wrap-region)
(wrap-region-add-wrapper "<div class=\"r-stack\">" "</div>")

(lambda (arg) (interactive p) (wrap-region-trigger arg <div class=“r-stack”>))

open graph

We want to create open graph descriptions and

	<!-- Open Graph -->
<meta property="og:title" content="technical blog">
<meta property="og:description" content="technical blog, a collection of articles/post written during 17y of career spanning over 3k3 source code files and 2k images">
<meta property="og:url" content="https://intertino.it/spiega/a/spiega.html">
<meta property="og:image" content="https://intertino.it/f/f_stage/module_library_small.png">
cd ~/lav/siti/f/f_stage/
for i in ~/lav/src/spiega/markdown/*.org;
do
    titN1=${i%.org}
    titN=${titN1##*/}
    cp module_library_small.png thumb_$titN.png
done

references

There are multiple guides with many different outcomes:

systemcrafters

convert folder

We mainly use following script to convert the documentation.

(org-publish-current-project)
#rm ~/lav/siti/spiega/a/*
#rm ~/lav/siti/scritti/p/*
cd $HOME/lav/src/spiega
bash ./script/convert.sh
elogio noia
/home/sabeiro/lav/siti/scritti//a/elogio_noia.html

hugo

Here we test hugo which is nicely integrated with emacs and org-mode.

(use-package ox-hugo) (setq org-hugo-base-dir “~/lav/src/spiega/hugo”) (setq org-hugo-default-section-directory “post”)

#+hugo_base_dir:
export HUGO_BASE_DIR="~/lav/src/spiega/hugo/"
cd ~/lav/src/spiega/
hugo new project cios
cd quickstart
git init
git submodule add https://github.com/gohugo-ananke/ananke themes/ananke
echo "theme = 'ananke'" >> hugo.toml
hugo server

hugo templates

Hugo works with templating:

hugo.toml
config file
content/
where to put the .html files
data/
data files (like for maps)
assets/
theme assets
layouts/
layout of partial snippets
static/
css, js
themes/
pre-made themes

Hugo uses macros to read the content from folders and replace variables:

<meta charset="utf-8">
<title>{{ print .Page.Title }}</title>
{{ $style := resources.Get "assets/sass/main.scss" | css.Sass }}
<link rel="stylesheet" href="{{ $style.Permalink }}">

hugo examples

A typical layout of index.html

{{ define "main" }}
<section class="intro">
  <p class="intro__eyebrow">visitor@{{ .Site.Params.prompt.host | default "blog" }} $ cat about.txt<span class="cursor">&nbsp;</span></p>
  <h1>{{ .Site.Params.tagline | default .Site.Title }}</h1>
  {{ with .Site.Params.description }}<p>{{ . }}</p>{{ end }}
</section>

{{ $sectionPages := where .Site.RegularPages "Type" "posts" }}
{{ if eq (len $sectionPages) 0 }}{{ $sectionPages = .Site.RegularPages }}{{ end }}
{{ $paginator := .Paginate $sectionPages }}

<p class="section-label">Recent posts</p>
<ul class="post-list">
  {{ range $i, $p := $paginator.Pages }}
    {{ partial "post-card.html" (dict "page" $p "index" $i) }}
  {{ else }}
    <li style="color: var(--overlay1); font-family: 'IBM Plex Mono', monospace;">No posts yet — create one with <code>hugo new posts/my-first-post.html</code>.</li>
  {{ end }}
</ul>

{{ partial "pagination.html" $paginator }}
{{ end }}

blog

Let’s find a way to create a blog out of a folder of org files.

References: ref1, ref2, ref3, ref4, ref5 The idea is to come closer to the style of adhdecode, markaicode, solariz

content management system

A wordpress approach:

(use-package org2blog) ;;uses wordpress

table of content

We want to create an index file from table of content

(defun org-toc ()
  (interactive)
  (let ((files (f-entries "." (lambda (f) (f-ext? f "org")) t))
    (headlines '())
    choice) 
    (loop for file in files do
      (with-temp-buffer 
        (insert-file-contents file) 
        (goto-char (point-min))
        (while (re-search-forward org-heading-regexp nil t)
          (cl-pushnew (list
               (format "%-80s (%s)"
                   (match-string 0)
                   (file-name-nondirectory file))
               :file file
               :position (match-beginning 0))
              headlines))))
    (setq choice
      (completing-read "Headline: " (reverse headlines)))
    (find-file (plist-get (cdr (assoc choice headlines)) :file))
    (goto-char (plist-get (cdr (assoc choice headlines)) :position))))

slides

slides

Here we use two main libraries

reveal
reveal.js example org to reveal
custom
org-export-reveal.el for batch processes run in convert.sh

reveal_slide.png

reveal

There are multiple options to turn org files into reveal slides

custom
org-export-reveal.el and reveal_config for batch processes run in convert.sh
(require 'ox-publish)
(use-package ox-reveal)
(setq org-reveal-root "../reveal/")
(setq org-re-reveal-root "../reveal/")
(setq org-reveal-hlevel 1) 
(use-package oer-reveal)
(setq oer-reveal-publish-org-publishing-functions
      '(oer-reveal-publish-to-reveal))
(setq org-html-toc nil
      org-html-footnotes-in-header-file nil
      org-html-footnotes-after-body nil
      org-html-footnotes-as-uid t
      org-export-with-broken-links t
      org-export-with-toc nil
      org-export-with-section-numbers nil
      org-export-with-sub-superscripts nil
      org-html-verbatim "verbatim"
      org-use-sub-superscripts nil
      org-html-wrap-src-lines t
      org-html-prefer-user-labels t
      org-export-babel-evaluate nil 
      org-html-footer nil
      )

reveal customization

The current setup is reveal_config where the main features are ref:

#+REVEAL_THEME:league
#+REVEAL_TITLE_SLIDE: title.html
#+REVEAL_INIT_OPTIONS: slideNumber:true
#+REVEAL_SLIDE_HEADER:
#+REVEAL_SLIDE_FOOTER:
#+REVEAL_EXTRA_CSS: url-to-custom-stylesheet.css
#+REVEAL_EXTRA_SCRIPT_SRC: url-to-custom-script

Multiplexing (users can change slides in presentation mode)

#+REVEAL_MULTIPLEX_ID: [Obtained from the socket.io server. ]
#+REVEAL_MULTIPLEX_SECRET: [Obtained from socket.io server. Gives the master control of the presentation.]
#+REVEAL_MULTIPLEX_URL:  https://reveal-multiplex.glitch.me [Location of socket.io server]

reveal usage

Some inline commands while writing org

Split a slide if the section is too long

#+REVEAL: split:t

change the section background

:PROPERTIES:
:reveal_background: #123456
:END:

change the image background

:PROPERTIES:
:reveal_background: ./images/whale.jpg
:reveal_background_trans: slide
:END:

iframe background

:PROPERTIES:
:reveal_background_iframe: https://hakim.se
:reveal_background: rgb(0,0,0)
:reveal_background_opacity: 0.8
:END:

fragment (transition) lists

#+ATTR_REVEAL: :frag (grow shrink roll-in fade-out none) :frag_idx (4 3 2 1 -)
   - I will grow.
   - I will shrink.
   - I rolled in.
   - I will fade out.
   - I don't fragment.

auto animate

* Heading 1
  :PROPERTIES:
  :REVEAL_EXTRA_ATTR: data-auto-animate
  :END:
  #+ATTR_REVEAL: :data_id foo
  #+begin_src js
    let index = 1
  #+end_src

Literal html

#+REVEAL_HTML

Speakers note

 * Heading 1
   Some contents.
#+BEGIN_NOTES
  Enter speaker notes here.
#+END_NOTES

Global properties

#+REVEAL_HLEVEL: 2
#+REVEAL_INIT_OPTIONS: transition: 'cube'
#+REVEAL_THEME: moon

Sub-heading properties

:PROPERTIES:
:EXPORT_REVEAL_HLEVEL: 2
:EXPORT_INIT_OPTIONS: transition: 'cube'
:EXPORT_REVEAL_THEME: moon
:END:

reveal export

Here it gets a bit confusing with all packages:

ox-reveal :: org-reveal :: org-re-reveal :: for of oer oer-reveal ::

We use the template

org-tree-slide

Here we use (org-tree-slide-mode) which basically displays and org file as slides. Navigation:

change section
[C-<] [C->]
show content
[C-x s c]
presets
simple
(org-tree-slide-simple-profile)
presentation
(org-tree-slide-presentation-profile)
narrow
no todos (org-tree-slide-narrowing-control-profile)
timer
(org-tree-slide-play-with-timer)
(use-package org-tree-slide
  :custom (org-image-actual-with nil))
(global-set-key (kbd "<f8>") 'org-tree-slide-mode)
(global-set-key (kbd "S-<f8>") 'org-tree-slide-skip-done-toggle)
(setq org-tree-slide-in-effect t
      org-tree-slide-activate-message "presentation started"
      org-tree-slide-deactivate-message "presentation ended"
      org-tree-slide-header t
      org-tree-slide-breadcrumbs " // "
)           

We can show the images in the file: (org-toggle-inline-images)

nil

slide generation from .org and .html

emacs has a lot of publishing options but in some cases I need a really custom design and therefore I strip header and footer from the html and append my own. We have a bash file for that convert_slide.sh. I need as well to convert the mermaid svg graph into a format blender can import which means first of all to convert the plain text into path which is accomplished by text2svg. This script tries as well to rename path ids to allow easier grouping into blender.

cd $HOME/lav/src/spiega/script/
bash ./convert.sh 
#bash ./text2svg.sh
###        /home/sabeiro/lav/src/spiega/article//documentation_present.org

two columns

We need to wrap the two columns into a div

scale architecture

This is a design sketch on how to scale this workflow for multi-user system

org
keeps track of agendas, tasks, project notes, deadlines, and authored knowledge
hugo
can publish curated pages such as project documentation, procedures, decisions, and reference material
tags
a rule for what is publishable, how links, attachments, tags map to site structure
knowledge graph
structured meaning and relationships: people, projects, tasks, documents, headings, tags, deadlines, links, permissions, and their connections. It answer relationship-oriented questions
search layer
finding relevant content quickly, typically using text and semantic matching.
parser
extract headings, properties, tags, IDs, links, timestamps, TODO states, schedules, deadlines, drawers, and selected planning metadata
linter
a special util inside the editor should check per user-group what changes make sense before committing

org processing

We need to build an org-processor and a non-tech-user UI for editing some labels

map
into a defined semantic model or knowledge graph. Hugo could remain the employee-facing interface, while the graph and retrieval layer support relationships and semantic search.
sync
decide how changes are synchronized
access
tech users to access org-repository. UI users for curated documentation, project views, task summaries, and semantic search.
labels
sensitive content should be filtered out or enforced through query-time permissions
pipeline
Org repo → parser and validation → knowledge graph → role-aware internal web UI
semantic search
current task views, relationship navigation, and role-aware results
permissions
a narrowly scoped update API for employee-editable fields such as task status or approved labels
validation
updates would be validated, written back to Org, and then re-indexed into the knowledge graph and search layer
collision
server-authoritative document model, real-time synchronization, user presence, version history, and conflict handling—often through operational transformation or CRDT-style techniques
change review
submit changes only to approved properties or tags through the UI; the service validates the change, records the user and timestamp, applies it to Org through one write path, and re-indexes the graph and search projections

architecture design

A draft of architecture would be:

repo
where all the org-files are stored
linter
a consistency check on information (end-date > start-date…)
commit
a series of allowed changes and permissions
sensitivity
sensitivity labels (inherit)

mermaid

---
displayMode: compact
title: Current Agenda Timeline from Clock Logs
config:
  gantt:
      useWidth: 900
      rightPadding: 20
      topAxis: true
      numberSectionStyles: 3
---
gantt
    dateFormat  YYYY-MM-DD
    title  Agenda Items Timeline from Clock Logs
    excludes  weekends

    section in progress
        agenda_review          :done,   rev1, 2026-09-07, 3d
        video_prep_org         :active,  v1, 2026-09-06, 5d
        video_prep_animations  :active,  v2, 2026-09-09, 3d

        soundtrack_finish      :active,  s1, 2026-09-16, 5d

        llm_chat               :done,   llm1, 2026-09-14, 1d
        llm_gptel              :active,  llm2, 2026-09-15, 3d
        llm_ellama            :active,  llm3, 2026-09-19, 2d
        llm_coding_assistant  :active,  llm4, 2026-09-20, 3d

        reporting_basic        :active,  rep1, 2026-09-15, 3d

    section active
        emacs_conf             :active,  e1, 2026-09-19, 3d

    section recurrent
        housekeeping           :active,  h1, 2026-09-18, 2d
        publish_sync           :active,  p1, 2026-09-18, 1d

    section knowledge
        integrate_llm_emacs    :active,  k1, 2026-09-14, 5d

    section milestone
        video_production       :milestone, m1, 2026-09-27, 1d
---
config:
  kanban:
    ticketBaseUrl: 'https://mermaidchart.atlassian.net/browse/#TICKET#'
---
kanban
  Todo
    [TODO-1] Parse agenda items
    [TODO-2] Extract clock logs
    [TODO-3] Generate gantt timeline
    [TODO-4] Create kanban board
    [TODO-5] Validate output format
  In Progress
    [PROG-1] Convert org headers to tasks
    [PROG-2] Map TODO states to kanban columns
    [PROG-3] Schedule date extraction
    [PROG-4] Effort estimation parsing
  Review
    [REV-1] Check gantt spacing
    [REV-2] Validate task names
    [REV-3] Test with sample agenda
  Done
    [DONE-1] Extract task headers
    [DONE-2] Parse clock entries
    [DONE-3] Generate mermaid syntax
    [DONE-4] Create visualization
     present this documentation
postamble