Research Preview

Open source · Reporting as Code

Reporting as Code. Strictly IBCS®.

Write the report in YAML and SQL, and bino will render it as an IBCS PDF. The files are stored in Git, so every change is reviewed and each report can be recreated.

The tutorial runs in your browser. It guides you through creating a PDF from your first manifest, with no installation required.

bino-bi/bino-cli6$ brew install bino-bi/tap/bino-cli
Follow this report
  • YAML and SQL
  • Query engine included, powered by DuckDB
  • PDF from a headless browser on the Chromium engine
  • IBCS notation
  • Reviewed in Git
  • Built in CI
  • MCP server for agents
  • Language server
  • AGPL-3.0

One report, start to finish

From a CSV file to a PDF in four steps

Kestrel Outdoor GmbH is a fictitious company with a genuine report. Scroll through the files that make it up. Next to each file, you can see the data or what bino built at that stage.

Step 1 of 4

Point bino at the data

A DataSource refers to a file, database or URL, which bino loads under its name into the included query engine, powered by DuckDB. In this example, it is a CSV file with 240 rows: month, region, product line, revenue and cost of goods, showing actual, plan and last year figures.

datasources/kestrel.yamlyaml
apiVersion: bino.bi/v1alpha1
kind: DataSource
metadata:
  name: kestrel
  description: Fictional monthly revenue and cost of goods 2025 (AC, PY, PL) of Kestrel Outdoor GmbH
spec:
  type: csv
  path: ../data/kestrel_2025.csv
Open datasources/kestrel.yaml
data/kestrel_2025.csv240 rows · loaded as kestrel
First rows of data/kestrel_2025.csv
monthregionproductrevenue_acrevenue_pyrevenue_plcogs_accogs_pycogs_pl
2025-01-01NorthTents472004350046900274002550027200
2025-01-01NorthBackpacks364003380037300193001780019400
2025-01-01NorthApparel304003080033100142001460015600
2025-01-01NorthFootwear210001860020700118001030011400
2025-01-01SouthTents626005590061900338003110034100
2025-01-01SouthBackpacks516004550049200252002270024300
2025-01-01SouthApparel431003970043700196001790019500
2025-01-01SouthFootwear285002590027300151001370014300

Step 2 of 4

Shape it with SQL

A DataSet is a SQL query. This one adds up the months. Months after REPORT_MONTH become a forecast: plan times the ratio of actual to plan so far.

datasets/monthly.yamlyaml
apiVersion: bino.bi/v1alpha1
kind: DataSet
metadata:
  name: monthly
  description: >-
    Revenue per month in kEUR. Months up to REPORT_MONTH are actual (ac1), later months are a
    run-rate forecast (fc1): plan times the year-to-date ratio of actual to plan.
spec:
  dependencies: [kestrel]
  query: |
    WITH m AS (
      SELECT month, SUM(revenue_ac) AS ac, SUM(revenue_pl) AS pl, SUM(revenue_py) AS py
      FROM kestrel GROUP BY month
    ),
    rate AS (
      SELECT SUM(ac) / SUM(pl) AS r FROM m WHERE month(month) <= ${REPORT_MONTH:12}
    )
    SELECT
      strftime(month, '%Y-%m-%d') AS date,
      CASE WHEN month(month) <= ${REPORT_MONTH:12} THEN ROUND(ac / 1000) END AS ac1,
      CASE WHEN month(month) > ${REPORT_MONTH:12} THEN ROUND(pl * rate.r / 1000) END AS fc1,
      ROUND(pl / 1000) AS pl1,
      ROUND(py / 1000) AS pp1
    FROM m, rate
    ORDER BY month
Open datasets/monthly.yaml
The ChartTime component built from this DataSet: revenue per month against plan, with the relative variance on top.
components/monthly_chart.yaml, rendered by a bino ScreenshotArtefact with REPORT_MONTH=8

Step 3 of 4

Describe the page

A LayoutPage places a chart, a table and a text. It also writes the IBCS title: who, what, when.

pages/monthly.yamlyaml
apiVersion: bino.bi/v1alpha1
kind: LayoutPage
metadata:
  name: monthly
  description: Revenue by month and region, year to date
spec:
  selectedStyle: kestrel
  pageFormat: a4
  pageOrientation: landscape
  pageLayout: custom-template
  pageCustomTemplate: '"a a a a" "a a a a" "b b b c"'
  pageGridGap: "12"
  titleBusinessUnit: Kestrel Outdoor GmbH
  titleMeasures:
    - name: Revenue
      unit: kEUR
  titleScenarios: [ac1, fc1, pl1, pp1]
  titleVariances: [dac1_pl1_pos, drac1_pl1_pos]
  titleDateStart: "2025-01-01"
  titleDateEnd: "2025-12-31"
  titleDateFormat: month
  titleDateLink: interval
  footerText: "Fictional data: data/kestrel_2025.csv"
  children:
    - kind: ChartTime
      ref: monthly_chart
    - kind: Table
      ref: region_table
    - kind: Text
      ref: commentary
Open pages/monthly.yaml
The page built for August: actual months are solid, September to December are a hatched forecast.
pages/monthly.yaml, built with REPORT_MONTH=8

Step 4 of 4

Build the PDF

bino build validates every file, runs the queries and prints the pages using a headless Chromium-based browser. The same command can be used on your laptop or in CI, so the PDF can always be recreated.

reports/kestrel.yamlyaml
apiVersion: bino.bi/v1alpha1
kind: ReportArtefact
metadata:
  name: kestrel
  description: The full report, four pages
spec:
  filename: kestrel-2025.pdf
  title: Kestrel Outdoor GmbH - Revenue and gross profit 2025
  language: en
  format: a4
  orientation: landscape
  layoutPages: [monthly, structure, profit, portfolio]
Open reports/kestrel.yaml
BINO 0.100.0
 
ℹ INFO build: Using template engine v1.0.0-next.29
→ Loading manifests...
✓ Validated 35 document(s) (24ms)
 
ℹ Manifest summary:
 
→ Building 1 artefact(s)...
→ Rendering kestrel...
 
Generated 1 artefact(s):
  • kestrel → dist/kestrel-2025.pdf (+graph)
 
✓ Build complete in 1.04s

Monthly close

Same files.
Twelve months.

REPORT_MONTH is an environment variable. Each frame here shows a real bino build of the same page from January to December. The actual months turn solid, the forecast remains hatched and a SQL query writes the comment.

$ REPORT_MONTH=5 bino build --artefact monthly✓ Build complete in 1.03s

Pick a month, or use the arrow keys.

The monthly report as bino built it with REPORT_MONTH=5.

Agentic reporting

An agent writes the report. bino checks it.

A bino report is plain YAML and SQL, so an AI agent can write it. bino mcp provides the agent with the tools to read your data, review every draft and produce the final result. The IBCS rules remain unchanged. The agent is just another way of writing the report.

This video shows a real run: an agent built an IBCS report from a CSV file with only the bino tools, and a person reviewed the PDF twice.See the prompt, the reviews, every tool call and the PDFs →
  1. 1validate_draft

    Check the draft

    The agent writes a manifest and bino validates it against the schema in memory before anything is saved.

  2. 2write_manifest

    Write it

    bino only writes the manifest to disk after validating it again.

  3. 3get_rows

    Check the numbers

    The agent queries its own DataSet and compares the rows with what should be on the page.

  4. 4build

    Render the PDF

    It is the same bino build as on your computer. The PDF is what you review.

Handout

An agent can build your report in minutes. Can you trust it?

The case for agentic reporting in two pages: six points of criticism and how bino addresses each one. Print it out for the next meeting.

Projects

One workflow, three projects

bino cli is open source and licensed under AGPL-3.0. The sandbox and the registry are free hosted services built around it.

bino cliOpen source

IBCS reports from YAML + SQL

$ brew install bino-bi/tap/bino-cli

Report-as-code runtime in the browser

Share report definitions with the community

$ bino registry add @acme/base-layout

Plugins · early access

Extend bino with plugins

A plugin adds data sources, visual components, lint rules, pipeline hooks or commands to bino. You write it in Go with the plugin SDK (Apache-2.0). The SDK is at v0.0.x, so the API can still change.

Built in the open

bino gets better with every question.

bino is developed publicly on GitHub. It is your questions, ideas and bug reports that determine what comes next. Choose the most appropriate channel, or contact the developer directly.

bino-bi/bino-cli6AGPL-3.0
  • Ask and discuss

    Ask a question, share how you use bino, or suggest a new chart or data source. As threads are public, the next person will find the answer too.

  • Report a bug

    Did something render incorrectly or did a command fail? The issue form asks for your bino version and a small example of the problem. This is often all that is needed to resolve the issue.

  • Write to the developer

    For what does not belong in public: your own reports, a pilot in your team, support, or working together. You get an answer by e-mail.

Your turn

Your first report is three commands away.

bino init standard writes a full starter report: a CSV data source, a dataset, an IBCS table and chart, a style and translations. bino preview shows it in your browser and reloads on every save.

Need help running bino in your team? See services →
Questions about your reports, a bug, or working together? Write to us →

Terminalbash
$ brew install bino-bi/tap/bino-cli
$ bino init standard --directory my-report
$ cd my-report && bino preview