obsidian-charts — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited obsidian-charts (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Assumes the user already has the Charts community plugin (phibr0/obsidian-charts) installed and enabled.
Before writing any codeblock, pick the source — it changes the syntax:
| Source | Use when | Pattern |
|---|---|---|
| Inline literal | Small, hand-typed series | chart codeblock with labels: + series: |
| Markdown table in same note | Data already lives in a table | chart codeblock with id: <blockId> |
| Markdown table in another note | Shared data table | chart codeblock with id: + file: |
| Dataview / Dataviewjs query | Data is computed/aggregated | dataviewjs codeblock calling window.renderChart(...) |
| Frontmatter values | Comparing notes by property | Dataviewjs + renderChart (Dataview required) |
If the user is unsure, look at the note. A table → use table linking. A query → use renderChart. Loose numbers in prose → inline literal.
type: bar labels: [Mon, Tue, Wed, Thu, Fri] series:
data: [4, 3, 5, 2, 6] beginAtZero: true width: 80%
| | Q1 | Q2 | Q3 | Q4 |
| - | - | - | - | - |
| Revenue | 10 | 14 | 12 | 18 |
| Cost | 8 | 9 | 11 | 13 |
^revenue
type: bar id: revenue layout: rows beginAtZero: true
layout: rows reads each table row as a series; layout: columns reads each column as a series. Add select: [Revenue] to restrict which rows/columns are charted. Add file: <OtherNote> to point at a ^blockId in another note.
Requires the Dataview plugin with JS enabled.
const pages = dv.pages('"Journal"').where(p => p.mood); window.renderChart({ type: 'line', data: { labels: pages.map(p => p.file.name).array(), datasets: [{ label: 'Mood', data: pages.map(p => p.mood).array(), tension: 0.3, }] } }, this.container);
| Key | Values | Notes | |
|---|---|---|---|
type | bar line pie doughnut radar polarArea | Required | |
labels | [a, b, c] | Required for non-table source | |
series | list of { title, data } | Required for non-table source | |
id | block ID | Use instead of labels/series to pull from a table | |
file | note basename | Pairs with id for cross-note tables | |
layout | rows \ | columns | Table-source only |
select | [name1, name2] | Filter rows/cols from a table | |
beginAtZero | bool | Force y-axis to start at 0 | |
stacked | bool | Stack series (bar/line) | |
tension | 0–1 | Line curve smoothing | |
fill | bool | Fill area under line | |
width | 80% etc. | Chart width | |
legend | bool | Show legend | |
legendPosition | top bottom left right | ||
bestFit | bool | Draw trend line (line/scatter) | |
bestFitTitle | string | Label for trend line | |
bestFitNumber | number | Series index for trend | |
labelColors | bool | Color labels by series | |
time | day month year etc. | Treat labels as dates | |
indexAxis | x \ | y | y makes horizontal bar chart |
xMin xMax yMin yMax | number/date | Axis bounds | |
xTitle yTitle | string | Axis labels |
See REFERENCE.md for the full parameter list, renderChart API, color/styling, multi-series patterns, and troubleshooting.
^blockId?), a query result, or loose values.bar. Trend over time → line. Parts of a whole → pie / doughnut. Multi-dimensional → radar.^blockId line beneath it. If not, add one — without it, the chart cannot reference the table.rows vs columns is the most common "why is my chart wrong" issue. If the chart looks transposed, flip it.^blockId must be on its own line immediately after the table, and id: in the codeblock must match exactly (no ^).rows ↔ columns.time: day (or month/year) so the plugin treats labels as dates.dataviewjs (it must be — dataview won't work for JS).data array must match labels.length (pad with null for missing points).~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.