Cozy Data Science Command Center
Design a unified Obsidian vault with automated dashboards and one-hotkey project creation.
Introduction
30 Second Summary
The space where you work shapes how you think. A cluttered, inconsistent workspace creates friction every time you sit down to focus.
In this project, you will redesign your Obsidian vault with a cohesive visual system and automated workflows that make managing data science projects feel effortless and beautiful.
What You'll Build
A complete vault redesign that replaces patchwork styling with a unified "Maison" design system, a live dashboard, and one-keystroke project creation.
By the end of this project, you'll have:
- A Style Settings JSON preset and single CSS snippet that apply a warm cream-and-sage palette across the entire vault.
- An auto-updating dashboard that surfaces your highest-priority tasks, active projects with progress bars, and today's agenda.
- A one-hotkey project creation workflow that generates a complete data science project folder with consistent structure and metadata.
- Secret Mission: Add an automated weekly review note that catches stalled experiments and overdue tasks.
Are there any prerequisites?
You need Obsidian installed with the Baseline theme, Style Settings, Dataview, and Templater plugins already enabled.
You should be comfortable with Obsidian basics like creating notes and navigating your vault.
Reset and Install QuickAdd
Your vault currently has a patchwork theme-maison.css snippet built up from incremental styling sessions. Before layering on a new design system, you need a clean baseline to work from.
In this step, you'll disable the old snippet, install the QuickAdd plugin for automation, and confirm your existing plugins are ready to go.
In this step, get ready to:
- Disable the existing theme-maison.css snippet.
- Install and enable the QuickAdd plugin.
- Confirm all required plugins are active and configured.
Disable the existing theme-maison.css snippet
The old snippet applied styling inconsistently across your vault. Disabling it gives you a neutral canvas for the new Maison design system you'll build in the next step.
- In Obsidian, click the gear icon in the bottom-left corner to open Settings.
- Click Appearance in the left sidebar.
- Scroll down to the CSS snippets section.
- Find theme-maison.css in the list and toggle it OFF.
Your vault should now show default Baseline theme styling. Any custom colors or card effects from the old snippet will disappear.
Why keep the file instead of deleting it?
Keeping the file as a backup means you can re-enable it later if you want to compare your old styling with the new system. Disabling is reversible. Deleting is not.
Still seeing custom styling after toggling off?
Make sure you toggled off the correct snippet. If you have multiple .css files in the list, check that the one labelled theme-maison specifically is disabled.
Try closing and re-opening the note you're viewing. Some cached styles clear on note reload.
Why is my vault still showing custom styles after disabling the snippet?
Install the QuickAdd plugin
QuickAdd lets you create reusable automation macros that run from the command palette or a hotkey. You'll use it later to spin up new data science projects with a single keystroke.
- In Settings, click Community plugins in the left sidebar.
- Click Browse.
- Type QuickAdd in the search field.
- Find QuickAdd in the results and click Install.
- Once installed, click Enable.
- Close the plugin browser by clicking the X in the top-right corner.
Press Cmd+P (macOS) or Ctrl+P (Windows) to open the command palette. Type QuickAdd. You should see QuickAdd commands appear in the results.
Don't see QuickAdd in the command palette?
Make sure you clicked both Install and Enable. Installing alone does not activate the plugin.
Try closing and reopening Settings, then check that QuickAdd shows a toggle in the Community plugins list.
Help me troubleshoot why QuickAdd isn't appearing in my command palette.
Confirm your existing plugins are enabled
The design system and dashboard you'll build depend on several plugins working together. A quick check now prevents confusing errors later.
- In Settings, click Community plugins.
- Verify that dataview shows an enabled (toggled ON) state.
- Verify that templater-obsidian shows an enabled (toggled ON) state.
- Verify that obsidian-style-settings shows an enabled (toggled ON) state.
- Verify that homepage shows an enabled (toggled ON) state.
- Click Templater in the left sidebar under Plugin Options.
- Confirm that Template folder location is set to Templates/.
What does each plugin do?
- Dataview powers the dynamic queries that pull task and project data into your dashboard.
- Templater lets you create templates with logic like dates, prompts, and conditionals.
- Style Settings exposes theme variables as toggles and sliders you can adjust without writing CSS.
- Homepage automatically opens a specific note (like your dashboard) when you launch Obsidian.
Missing a plugin from the list?
If any plugin is missing, click Browse, search for it by name, install it, and enable it.
If Templater's template folder is empty, type Templates/ into the field.
Help me figure out which plugins I'm missing and how to install them.
Your vault is now a clean canvas with all the right plugins ready. Next up, you'll import the Maison design system and watch your vault transform.
Apply the Maison Design System via Style Settings
In Step 1, you cleared out the patchwork CSS and set up QuickAdd. Your vault is now running on default Baseline styling, which looks clean but generic.
Instead of tweaking individual CSS variables one by one, you'll import a single JSON preset into Style Settings that defines your entire color palette, layout behavior, and font stack in one step. This is the foundation of the Maison design system.
In this step, get ready to:
- Import the Maison color palette preset into Style Settings.
- Configure Baseline's personality for rounded, Apple-like interface elements.
- Set typography for a warm, magazine-quality reading experience.
Import the Maison palette preset into Style Settings
The Maison preset is a JSON object that maps Baseline theme variables to your chosen coastal palette. Importing it sets colors, fonts, roundness, and layout behaviors in one action.
- Open Settings (Cmd+, on macOS or Ctrl+, on Windows).
- In the left sidebar, scroll down to Style Settings under Community plugins.
- Click the Import button in the top-right corner of the Style Settings pane.
- Paste the following JSON into the import text area:
{
"baseline-style@@background-primary@@light": "#FAF8F5",
"baseline-style@@background-primary@@dark": "#1C1B19",
"baseline-style@@background-contrast-light": "contrast-light-low",
"baseline-style@@background-contrast-dark": "contrast-dark-tonal",
"baseline-style@@color-red-rgb@@light": "#C4554D",
"baseline-style@@color-red-rgb@@dark": "#E07B73",
"baseline-style@@color-green-rgb@@light": "#5C8A6B",
"baseline-style@@color-green-rgb@@dark": "#7BAF8B",
"baseline-style@@color-blue-rgb@@light": "#5B7E95",
"baseline-style@@color-blue-rgb@@dark": "#7FA8BF",
"baseline-style@@font-interface-override": "Avenir, Montserrat, Corbel, 'URW Gothic', source-sans-pro, system-ui",
"baseline-style@@font-text-override": "Charter, 'Bitstream Charter', 'Sitka Text', Cambria, serif",
"baseline-style@@inline-title-font": "Avenir, Montserrat, Corbel, 'URW Gothic', source-sans-pro, system-ui",
"baseline-style@@radius-modifier": 1.25,
"baseline-style@@icon-stroke-modifier": 0.75,
"baseline-style@@layout-style": "layout-baseline",
"baseline-style@@status-bar-style": "status-bar-cupertino",
"baseline-style@@anim-motion-baseline": "cubic-bezier(0.32, 0.72, 0, 1)",
"baseline-style@@tab-style": "tab-underline",
"baseline-style@@metadata-style": "metadata-block",
"baseline-style@@blockquote-style": "blockquote-edge",
"baseline-style@@blockquote-border-thickness": 3
}
What does this preset do?
Each key follows the baseline-style@@setting-id format that Style Settings uses to map values to Baseline's theme variables.
- background-primary sets your vault background to warm cream (light) or deep charcoal (dark).
- color-green-rgb defines the sage green that will become your accent color.
- radius-modifier at 1.25 makes every corner in the UI slightly rounder than default.
- font-interface-override and font-text-override set the sans-serif and serif font stacks for headings and body text respectively.
- Click Import to apply the preset.
- Your vault background should shift to a warm cream tone. Text should appear in warm charcoal, and any accent-colored elements (links, toggle switches) should turn soft sage green.
Not seeing the color change?
- Make sure you clicked Import after pasting the JSON, not just closed the dialog.
- Check that the Baseline theme is still active in Settings > Appearance > Themes. Style Settings presets only work with the theme they target.
- Verify that the Style Settings plugin itself is enabled under Settings > Community plugins.
Why isn't my Style Settings preset applying to my vault?
✔️ Awesome, I've got everything!
Great. Make sure you keep the Settings pane open for the next substep.
ⓧ I'd like to double check the full code
Here is the complete JSON preset. Compare it character-by-character against what you pasted:
{
"baseline-style@@background-primary@@light": "#FAF8F5",
"baseline-style@@background-primary@@dark": "#1C1B19",
"baseline-style@@background-contrast-light": "contrast-light-low",
"baseline-style@@background-contrast-dark": "contrast-dark-tonal",
"baseline-style@@color-red-rgb@@light": "#C4554D",
"baseline-style@@color-red-rgb@@dark": "#E07B73",
"baseline-style@@color-green-rgb@@light": "#5C8A6B",
"baseline-style@@color-green-rgb@@dark": "#7BAF8B",
"baseline-style@@color-blue-rgb@@light": "#5B7E95",
"baseline-style@@color-blue-rgb@@dark": "#7FA8BF",
"baseline-style@@font-interface-override": "Avenir, Montserrat, Corbel, 'URW Gothic', source-sans-pro, system-ui",
"baseline-style@@font-text-override": "Charter, 'Bitstream Charter', 'Sitka Text', Cambria, serif",
"baseline-style@@inline-title-font": "Avenir, Montserrat, Corbel, 'URW Gothic', source-sans-pro, system-ui",
"baseline-style@@radius-modifier": 1.25,
"baseline-style@@icon-stroke-modifier": 0.75,
"baseline-style@@layout-style": "layout-baseline",
"baseline-style@@status-bar-style": "status-bar-cupertino",
"baseline-style@@anim-motion-baseline": "cubic-bezier(0.32, 0.72, 0, 1)",
"baseline-style@@tab-style": "tab-underline",
"baseline-style@@metadata-style": "metadata-block",
"baseline-style@@blockquote-style": "blockquote-edge",
"baseline-style@@blockquote-border-thickness": 3
}
Configure Baseline's personality and layout options
The JSON preset handled colors, fonts, and layout variables. One setting that needs to be configured manually is the interface personality, which controls the shape language of buttons, inputs, and interactive elements.
- In the Style Settings pane, navigate to the Interface section.
- Set Personality to input-cupertino. This gives buttons and inputs an iOS/macOS-inspired rounded appearance.
- Confirm that Status Bar Style is set to status-bar-cupertino. The preset should have applied this already.
- Confirm that Tab Style is set to tab-underline.
- Confirm that Roundness modifier is set to 1.25.
Buttons, inputs, and tabs should now have softer, rounded corners. The status bar at the bottom of Obsidian should have a compact, macOS-like appearance.
Why input-cupertino?
Baseline ships four personality options: input-baseline, input-adwaita, input-cupertino, and input-fluent. The Cupertino option mirrors Apple's design language with generous border-radius and subtle depth, which complements the soft Maison palette.
Personality dropdown not appearing?
If you do not see the Personality option under Interface, scroll up to make sure you are in the Baseline Style section of Style Settings (not a different theme or snippet section).
Help me find the Personality setting in Style Settings for Baseline theme.
Set typography in Obsidian Appearance settings
The preset configured Baseline's font override variables, but Obsidian also has its own native font settings under Appearance. Setting these ensures your chosen fonts are used everywhere, including places the theme variables might not reach.
- In the Settings sidebar, click Appearance.
- Set Interface font to: Avenir, Montserrat, system-ui.
- Set Text font to: Charter, 'Bitstream Charter', 'Sitka Text', Cambria, serif.
- Set Monospace font to: IBM Plex Mono, Menlo, monospace.
Headings and the Obsidian interface (sidebar, tabs) should now look clean and sans-serif. Body text in your notes should have a warm, literary serif feel. Any code blocks use a modern monospace font.
Why these font choices?
Avenir is bundled on macOS and gives a clean Apple-like feel for the interface. Charter is a warm serif designed for on-screen reading that ships with macOS. IBM Plex Mono is a modern monospace that feels professional without being overly technical.
On Windows, the fallback fonts (Montserrat, Cambria, Menlo) provide a similar aesthetic. If you do not have Avenir or Charter installed, the browser automatically falls through to the next available font in the stack.
Fonts not changing?
- Make sure you typed the font names exactly as shown, including the quotes around multi-word font names like 'Bitstream Charter'.
- Try closing and reopening a note to see the font change take effect.
- If you are on Windows and the sans-serif font still looks generic, Montserrat can be downloaded for free from Google Fonts.
My Obsidian fonts aren't changing after I set them in Appearance settings.
Your vault now has a unified visual foundation. Every color, font, and corner radius follows the same Maison design language. Next up, you'll create a custom CSS snippet to style the dashboard cards that the preset alone cannot handle.
Create the Dashboard CSS Snippet
Your vault now wears the Maison color palette and typography. The cream background, sage accents, and serif body text are all in place through Style Settings.
Style Settings handles variables like colors and font stacks, but it cannot create new layout patterns. Card shadows, progress bars, hover animations, and custom scrollbars all require a dedicated CSS snippet.
In this step, get ready to:
- Create the maison.css snippet file in the vault's snippets folder.
- Enable the snippet and verify it applies to your dashboard.
- Confirm the maison-page cssclass on Home.md.
Create the new maison.css snippet file
Obsidian loads custom CSS from the .obsidian/snippets/ folder inside your vault. Any .css file placed here and toggled on will override theme defaults for specific selectors.
- Return to Settings and navigate to Appearance.
- Scroll down to the CSS snippets section.
- Click the folder icon to open the snippets folder in Finder (macOS) or File Explorer (Windows).
- Create a new file in this folder called maison.css.
- Open maison.css in any text editor and paste the following CSS:
/* Maison Design System - Cozy Command Center
Apple meets Anthropic meets Nancy Meyers */
/* ===== Dashboard Card Styling ===== */
.maison-page .dataview.dataview-container {
padding: 0;
}
.maison-page .maison-card {
background: var(--background-primary);
border: 1px solid var(--background-modifier-border);
border-radius: 12px;
padding: 20px 24px;
margin-bottom: 16px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04), 0 2px 8px rgba(0, 0, 0, 0.02);
transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.maison-page .maison-card:hover {
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06), 0 4px 12px rgba(0, 0, 0, 0.04);
transform: translateY(-1px);
}
.maison-page .maison-greeting {
font-family: var(--font-interface-theme);
font-size: 1.8em;
font-weight: 600;
color: var(--text-normal);
margin-bottom: 4px;
letter-spacing: -0.02em;
}
.maison-page .maison-date {
font-family: var(--font-interface-theme);
font-size: 0.9em;
color: var(--text-muted);
margin-bottom: 24px;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.maison-page .maison-section-title {
font-family: var(--font-interface-theme);
font-size: 0.75em;
font-weight: 600;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.08em;
margin-bottom: 12px;
margin-top: 28px;
}
.maison-page .maison-task-item {
padding: 8px 0;
border-bottom: 1px solid var(--background-modifier-border);
font-size: 0.9em;
color: var(--text-normal);
}
.maison-page .maison-task-item:last-child {
border-bottom: none;
}
.maison-page .maison-task-priority {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 8px;
vertical-align: middle;
}
.maison-page .maison-priority-high {
background: var(--color-red);
}
.maison-page .maison-priority-medium {
background: var(--color-orange);
}
.maison-page .maison-priority-low {
background: var(--color-green);
}
.maison-page .maison-progress-bar {
height: 4px;
border-radius: 2px;
background: var(--background-modifier-border);
margin-top: 8px;
overflow: hidden;
}
.maison-page .maison-progress-fill {
height: 100%;
border-radius: 2px;
background: var(--color-green);
transition: width 0.3s ease;
}
.maison-page .maison-project-header {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 4px;
}
.maison-page .maison-project-name {
font-family: var(--font-interface-theme);
font-weight: 600;
font-size: 1em;
color: var(--text-normal);
}
.maison-page .maison-project-percent {
font-family: var(--font-monospace-theme);
font-size: 0.8em;
color: var(--text-muted);
}
/* ===== Scrollbar refinement ===== */
.maison-page ::-webkit-scrollbar {
width: 6px;
}
.maison-page ::-webkit-scrollbar-thumb {
background: var(--background-modifier-border);
border-radius: 3px;
}
/* ===== Accent override for sage green ===== */
body.theme-light {
--accent-h: 150;
--accent-s: 25%;
--accent-l: 45%;
}
body.theme-dark {
--accent-h: 150;
--accent-s: 20%;
--accent-l: 55%;
}
What does this CSS do?
This snippet is scoped to notes with the maison-page cssclass. It only affects pages that opt in through frontmatter.
- Dashboard Card Styling creates rounded cards with soft shadows and a subtle lift on hover.
- Greeting and date classes give the dashboard header a warm, magazine-quality layout with uppercase date styling.
- Task and progress classes render priority dots, task lists with dividers, and thin progress bars that fill with green.
- Scrollbar refinement slims the scrollbar to 6px for a cleaner feel.
- Accent override sets the vault-wide accent color to sage green (HSL 150/25/45 for light mode, 150/20/55 for dark mode).
- Save the file.
Why a CSS snippet instead of more Style Settings?
Style Settings can only adjust variables the theme exposes. Creating new selectors like .maison-card and .maison-progress-bar requires raw CSS because these elements do not exist until your dataviewjs code creates them at runtime.
The snippet uses Obsidian's own CSS variables (--background-primary, --text-muted) so your cards automatically respect the Maison palette from Style Settings.
Enable the snippet
- Return to Settings > Appearance > CSS snippets.
- Click the refresh icon to reload snippets.
- Toggle ON maison.css.
- Open Home.md and switch to Reading mode.
You should see dashboard cards with warm shadows, rounded 12px corners, and proper spacing between elements.
Don't see any styling changes?
- Make sure you clicked the refresh icon before toggling. Obsidian does not detect new files automatically.
- Check that the toggle next to maison.css is turned ON (highlighted).
- Verify your file is named exactly maison.css (not maison.css.txt) in the snippets folder.
Help me figure out why my CSS snippet isn't showing in Obsidian.
Apply the maison-page cssclass to Home.md
The CSS snippet targets elements inside notes that have the maison-page class. This class is applied through cssclasses frontmatter at the top of the note.
- Open Home.md in editing mode.
- Check that the frontmatter at the top of the file includes the following:
---
cssclasses:
- maison-page
- wide
---
What do these cssclasses do?
- maison-page activates all the custom card and dashboard styles from your snippet.
- wide is a built-in Baseline class that removes the default line-width constraint so your dashboard uses the full pane width.
- If your frontmatter already has these classes from your previous setup, no change is needed.
- If they are missing, add the cssclasses block between the --- fences at the top of the file and save.
- Switch to Reading mode to confirm the page renders at full width with card styling applied.
You should see Home.md stretching to the full pane width. The Maison card styling is now ready for your dashboard content.
Page still looks narrow?
- Make sure wide is listed under cssclasses in the frontmatter, not as a tag or inline field.
- Confirm you are viewing in Reading mode. Editing mode may not reflect full-width rendering.
Help me get my Home.md to render at full width with cssclasses.
✔️ Awesome, I've got everything!
Great. Make sure you have saved maison.css and confirmed the snippet is toggled on in Appearance settings.
ⓧ I'd like to double check the full code
Here is the complete maison.css file for comparison:
/* Maison Design System - Cozy Command Center
Apple meets Anthropic meets Nancy Meyers */
/* ===== Dashboard Card Styling ===== */
.maison-page .dataview.dataview-container {
padding: 0;
}
.maison-page .maison-card {
background: var(--background-primary);
border: 1px solid var(--background-modifier-border);
border-radius: 12px;
padding: 20px 24px;
margin-bottom: 16px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04), 0 2px 8px rgba(0, 0, 0, 0.02);
transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.maison-page .maison-card:hover {
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06), 0 4px 12px rgba(0, 0, 0, 0.04);
transform: translateY(-1px);
}
.maison-page .maison-greeting {
font-family: var(--font-interface-theme);
font-size: 1.8em;
font-weight: 600;
color: var(--text-normal);
margin-bottom: 4px;
letter-spacing: -0.02em;
}
.maison-page .maison-date {
font-family: var(--font-interface-theme);
font-size: 0.9em;
color: var(--text-muted);
margin-bottom: 24px;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.maison-page .maison-section-title {
font-family: var(--font-interface-theme);
font-size: 0.75em;
font-weight: 600;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.08em;
margin-bottom: 12px;
margin-top: 28px;
}
.maison-page .maison-task-item {
padding: 8px 0;
border-bottom: 1px solid var(--background-modifier-border);
font-size: 0.9em;
color: var(--text-normal);
}
.maison-page .maison-task-item:last-child {
border-bottom: none;
}
.maison-page .maison-task-priority {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 8px;
vertical-align: middle;
}
.maison-page .maison-priority-high {
background: var(--color-red);
}
.maison-page .maison-priority-medium {
background: var(--color-orange);
}
.maison-page .maison-priority-low {
background: var(--color-green);
}
.maison-page .maison-progress-bar {
height: 4px;
border-radius: 2px;
background: var(--background-modifier-border);
margin-top: 8px;
overflow: hidden;
}
.maison-page .maison-progress-fill {
height: 100%;
border-radius: 2px;
background: var(--color-green);
transition: width 0.3s ease;
}
.maison-page .maison-project-header {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 4px;
}
.maison-page .maison-project-name {
font-family: var(--font-interface-theme);
font-weight: 600;
font-size: 1em;
color: var(--text-normal);
}
.maison-page .maison-project-percent {
font-family: var(--font-monospace-theme);
font-size: 0.8em;
color: var(--text-muted);
}
/* ===== Scrollbar refinement ===== */
.maison-page ::-webkit-scrollbar {
width: 6px;
}
.maison-page ::-webkit-scrollbar-thumb {
background: var(--background-modifier-border);
border-radius: 3px;
}
/* ===== Accent override for sage green ===== */
body.theme-light {
--accent-h: 150;
--accent-s: 25%;
--accent-l: 45%;
}
body.theme-dark {
--accent-h: 150;
--accent-s: 20%;
--accent-l: 55%;
}
Your design system now has two layers working together: Style Settings for colors and typography, and maison.css for layout and interaction. Next up, you will rebuild the dashboard content inside Home.md with dataviewjs that creates the card elements your CSS is ready to style.
Rebuild the Dashboard
Your vault now has a cohesive design system, but the dashboard itself still shows whatever content existed before.
In this step, you will rebuild Home.md into a full command center that greets you by time of day, surfaces your single highest-priority task, and shows live progress for every active project.
In this step, get ready to:
- Replace the existing Home.md content with a dataviewjs command center.
- Verify each dashboard section renders in Reading mode.
- Adjust the project query path if your folder structure differs.
Replace the dataviewjs block in Home.md
The Dataview plugin lets you write JavaScript that queries your vault and renders custom HTML. You will use a single dataviewjs block to build the entire dashboard.
- Open Home.md in your vault.
- Switch to Source mode by pressing Cmd+Click (macOS) or Ctrl+Click (Windows) on the editing mode toggle in the bottom-right corner, or use the command palette (Cmd+P / Ctrl+P) and search for "Toggle Live Preview/Source mode".
- Select all content below the frontmatter (everything after the closing ---) and delete it.
- Paste the following dataviewjs block in its place:
```dataviewjs
// === Maison Command Center ===
const container = dv.container;
// Greeting
const hour = new Date().getHours();
const greeting = hour < 12 ? "Good morning" : hour < 17 ? "Good afternoon" : "Good evening";
const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const dayName = days[new Date().getDay()];
const dateStr = new Date().toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });
container.createEl("div", { cls: "maison-greeting", text: `${greeting}, ${dayName}` });
container.createEl("div", { cls: "maison-date", text: dateStr });
// --- Up Next: highest priority task ---
container.createEl("div", { cls: "maison-section-title", text: "Up Next" });
const allTasks = dv.pages('"Projects"')
.file.tasks
.where(t => !t.completed)
.sort(t => t.text, 'asc');
const upNextCard = container.createEl("div", { cls: "maison-card" });
if (allTasks.length > 0) {
const task = allTasks[0];
upNextCard.createEl("div", { cls: "maison-task-item", text: task.text });
} else {
upNextCard.createEl("div", { cls: "maison-task-item", text: "All clear. Nothing due." });
}
// --- Active Projects ---
container.createEl("div", { cls: "maison-section-title", text: "Active Projects" });
const projects = dv.pages('"Projects"')
.where(p => p["pm-type"] === "project" && p["pm-status"] !== "archived" && p["pm-status"] !== "done");
for (const project of projects) {
const card = container.createEl("div", { cls: "maison-card" });
// Header row
const header = card.createEl("div", { cls: "maison-project-header" });
const projectTasks = dv.page(project.file.path).file.tasks;
const total = projectTasks.length;
const done = projectTasks.where(t => t.completed).length;
const percent = total > 0 ? Math.round((done / total) * 100) : 0;
const nameEl = header.createEl("a", { cls: "maison-project-name", text: project.file.name, href: project.file.path });
nameEl.classList.add("internal-link");
nameEl.setAttribute("data-href", project.file.path);
header.createEl("span", { cls: "maison-project-percent", text: `${percent}%` });
// Progress bar
const bar = card.createEl("div", { cls: "maison-progress-bar" });
const fill = bar.createEl("div", { cls: "maison-progress-fill" });
fill.style.width = `${percent}%`;
// Top open tasks for this project
const openTasks = projectTasks.where(t => !t.completed).slice(0, 4);
for (const t of openTasks) {
card.createEl("div", { cls: "maison-task-item", text: t.text });
}
}
```
What does this code do?
This single dataviewjs block builds three dashboard sections:
- Greeting checks the current hour to say "Good morning", "Good afternoon", or "Good evening" alongside today's day name and date.
- Up Next queries every incomplete task across all pages inside Projects/, sorts alphabetically, and shows just the first one. If nothing is due, it displays "All clear. Nothing due."
- Active Projects finds pages where pm-type is project and pm-status is not archived or done. Each project renders as a card with its name linked, a completion percentage, a progress bar, and up to 4 open tasks.
- Save Home.md.
- Switch to Reading mode by clicking the book icon in the top-right corner of the editor.
Seeing raw code instead of rendered output?
- Make sure you are in Reading mode, not Source mode or Live Preview. The dataviewjs block only renders in Reading mode.
- Confirm the Dataview plugin is enabled in Settings > Community plugins. If it was recently toggled off, re-enable it and reload Obsidian.
- Check that the opening fence reads exactly ```dataviewjs with no space between the backticks and the word.
Help me troubleshoot why my dataviewjs block isn't rendering in Obsidian.
Verify each dashboard section renders correctly
With Reading mode active, your dashboard should now display three distinct sections. Walk through each one to confirm it renders.
- Confirm the Greeting shows "Good morning", "Good afternoon", or "Good evening" followed by today's weekday name.
- Confirm the date line displays today's date in a format like "June 10, 2026".
- Confirm the Up Next section shows either a task name or "All clear. Nothing due." inside a card with rounded corners and a subtle shadow.
- Confirm the Active Projects section shows cards for any projects that have pm-type: project in their frontmatter. Each card should display a linked name, a percentage, and a green progress bar.
What if a section shows no results?
If the Active Projects section is empty, that is expected when no pages inside Projects/ have pm-type: project in their frontmatter. The same applies to Up Next if there are no incomplete tasks.
Once you create a project with the template in the next step, these sections will populate automatically.
Adjust the project query path if needed
The dataviewjs queries filter by the "Projects/" path. If your projects live in a subfolder (such as Projects/FY27 Q2/), you will need to update the path filter so Dataview finds them.
- Switch back to Source mode in Home.md.
- Find the two lines containing dv.pages('"Projects"').
- If your projects live in a deeper path, replace "Projects" with your actual folder path (for example, "Projects/FY27 Q2").
- Save Home.md and switch to Reading mode.
- Confirm that projects with pm-type: project frontmatter now appear as cards in the Active Projects section.
Keep the path broad
Dataview queries using a folder path like "Projects" search recursively through all subfolders. If you point the query at your top-level Projects/ folder, it will find notes in any subfolder beneath it automatically.
✔️ Awesome, I've got everything!
Great. Double check you have saved Home.md and that it renders correctly in Reading mode.
ⓧ I'd like to double check the full code
Here is the complete Home.md file including frontmatter. Make sure yours matches exactly.
---
cssclasses:
- maison-page
- wide
---
```dataviewjs
// === Maison Command Center ===
const container = dv.container;
// Greeting
const hour = new Date().getHours();
const greeting = hour < 12 ? "Good morning" : hour < 17 ? "Good afternoon" : "Good evening";
const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const dayName = days[new Date().getDay()];
const dateStr = new Date().toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });
container.createEl("div", { cls: "maison-greeting", text: `${greeting}, ${dayName}` });
container.createEl("div", { cls: "maison-date", text: dateStr });
// --- Up Next: highest priority task ---
container.createEl("div", { cls: "maison-section-title", text: "Up Next" });
const allTasks = dv.pages('"Projects"')
.file.tasks
.where(t => !t.completed)
.sort(t => t.text, 'asc');
const upNextCard = container.createEl("div", { cls: "maison-card" });
if (allTasks.length > 0) {
const task = allTasks[0];
upNextCard.createEl("div", { cls: "maison-task-item", text: task.text });
} else {
upNextCard.createEl("div", { cls: "maison-task-item", text: "All clear. Nothing due." });
}
// --- Active Projects ---
container.createEl("div", { cls: "maison-section-title", text: "Active Projects" });
const projects = dv.pages('"Projects"')
.where(p => p["pm-type"] === "project" && p["pm-status"] !== "archived" && p["pm-status"] !== "done");
for (const project of projects) {
const card = container.createEl("div", { cls: "maison-card" });
// Header row
const header = card.createEl("div", { cls: "maison-project-header" });
const projectTasks = dv.page(project.file.path).file.tasks;
const total = projectTasks.length;
const done = projectTasks.where(t => t.completed).length;
const percent = total > 0 ? Math.round((done / total) * 100) : 0;
const nameEl = header.createEl("a", { cls: "maison-project-name", text: project.file.name, href: project.file.path });
nameEl.classList.add("internal-link");
nameEl.setAttribute("data-href", project.file.path);
header.createEl("span", { cls: "maison-project-percent", text: `${percent}%` });
// Progress bar
const bar = card.createEl("div", { cls: "maison-progress-bar" });
const fill = bar.createEl("div", { cls: "maison-progress-fill" });
fill.style.width = `${percent}%`;
// Top open tasks for this project
const openTasks = projectTasks.where(t => !t.completed).slice(0, 4);
for (const t of openTasks) {
card.createEl("div", { cls: "maison-task-item", text: t.text });
}
}
```
Your command center is live. Next up, you will build a project template and wire it to a single hotkey so spinning up new data science projects takes one keystroke.
Build the Project Template and QuickAdd Macro
Your dashboard is live and looking sharp. Now it's time to solve the last piece of the workflow puzzle: creating new data science projects consistently.
Right now, spinning up a new project means manually creating folders, writing frontmatter, and remembering which metadata fields your dashboard expects. One missed field and the project disappears from your command center. In this step, you'll build a template and wire it to a single hotkey so that every new project starts with the right structure.
In this step, get ready to:
- Create a Templater template for data science projects.
- Configure a QuickAdd macro to generate projects from that template.
- Bind a hotkey for instant project creation.
Create the data science project Templater template
A Templater template is a markdown file with special syntax that gets evaluated when you create a new note from it. It can auto-fill today's date, prompt for a project name, and inject consistent frontmatter.
- In the Obsidian sidebar, navigate to Templates/Project Template/.
- Create a new file called DS Project.md inside that folder.
- Paste the following template content into the file:
---
cssclasses:
- wide
pm-type: project
pm-status: active
pm-priority: medium
created: <% tp.date.now("YYYY-MM-DD") %>
---
# <% tp.file.title %>
## Scope
- Objective:
- Success criteria:
- Timeline:
## Data Audit
| Source | Description | Access | Quality |
| ------ | ----------- | ------ | ------- |
| | | | |
## Tasks
- [ ] Define problem statement and success metrics
- [ ] Identify and audit data sources
- [ ] Exploratory data analysis
- [ ] Feature engineering
- [ ] Model development
- [ ] Validation and testing
- [ ] Write-up and presentation
## Findings
## Decisions
What does this template do?
The frontmatter includes pm-type: project and pm-status: active so that your Home.md dashboard automatically picks up the new project in the Active Projects section.
The <% tp.date.now("YYYY-MM-DD") %> tag auto-fills today's date when the template runs. <% tp.file.title %> inserts the file's name as the top-level heading, so you never need to type it twice.
The seven default tasks give every data science project a consistent starting checklist. Your dashboard's progress bar reads these to calculate completion percentage.
- Save DS Project.md.
- Confirm the file appears in the sidebar under Templates/Project Template/.
File not showing in the sidebar?
Make sure the file is saved inside Templates/Project Template/ and not at the vault root. Obsidian sometimes creates files in the wrong location if you use the quick switcher instead of the sidebar.
Also confirm your Templater plugin's template folder is set to Templates/ in Settings > Templater > Template folder location.
Template not appearing in the right folder?
Configure QuickAdd with a "New DS Project" macro
QuickAdd lets you turn any template into a one-click command. You'll create a Template choice that points at your new DS Project.md and automatically creates a folder for each project.
- Open Settings > QuickAdd.
- In the text field at the top of the QuickAdd pane, type New DS Project.
- Click Add Choice.
- Select type: Template.
- Click the gear icon on the new choice to open its configuration.
Inside the configuration panel, set the following options:
- Set Template Path to Templates/Project Template/DS Project.md.
- Set File Name Format to {{VALUE:Project Name}}.
- Set Create in folder to Projects/FY27 Q2/ (or your current projects folder).
- Toggle ON Create folder with same name as note.
What does {{VALUE:Project Name}} do?
When you trigger this macro, QuickAdd will prompt you to type a project name. That value becomes both the filename and (thanks to <% tp.file.title %> in the template) the top heading of the note. One input populates both places.
The "Create folder with same name as note" toggle means each project gets its own folder. This keeps related files (datasets, notebooks, images) co-located with the hub note.
- Close the gear configuration panel.
- Click the lightning bolt icon on the "New DS Project" choice to add it as a command.
- Open the command palette with Cmd+P (macOS) or Ctrl+P (Windows).
- Search for QuickAdd: New DS Project. It should appear in the results.
Command not appearing in the palette?
Make sure you clicked the lightning bolt icon (not the gear icon) on the choice. The lightning bolt registers it as a command palette entry.
If you still don't see it, try closing and reopening the command palette. Some changes require a palette refresh.
QuickAdd command not showing up?
Bind a hotkey for instant project creation
A command palette entry works, but a dedicated hotkey makes project creation feel instant. You'll bind the macro to a keyboard shortcut so you can trigger it from anywhere in your vault.
- Open Settings > Hotkeys.
- Search for QuickAdd: New DS Project.
- Click the + icon next to the command to assign a hotkey.
- Press Cmd+Shift+N (macOS) or Ctrl+Shift+N (Windows) to record the shortcut.
Now test the full workflow:
- Close Settings.
- Press your new hotkey (Cmd+Shift+N or Ctrl+Shift+N).
- When prompted, enter a test project name like Churn Prediction Model.
- Verify: a new folder appears under Projects/FY27 Q2/ with a hub note pre-filled with your template's frontmatter, heading, sections, and today's date.
What should I see?
The new note should open automatically. Its frontmatter will show pm-type: project and pm-status: active. The heading will read your project name. The seven task checkboxes will be ready to go.
Switch to Home.md in Reading mode. Your new project should appear as a card in the Active Projects section with 0% progress.
Project not appearing on the dashboard?
Open the new project note and check that the frontmatter includes pm-type: project and pm-status: active. Both fields are required for the Dataview query in Home.md to find it.
Also confirm the project file lives inside the Projects/ folder path. The dashboard's query filters by "Projects" so anything outside that folder is invisible to it.
New project not showing on my dashboard?
✔️ Awesome, I've got everything!
Great. Double check you've saved your template file and tested the hotkey at least once.
ⓧ I'd like to double check the full code
Here is the full template file for comparison:
---
cssclasses:
- wide
pm-type: project
pm-status: active
pm-priority: medium
created: <% tp.date.now("YYYY-MM-DD") %>
---
# <% tp.file.title %>
## Scope
- Objective:
- Success criteria:
- Timeline:
## Data Audit
| Source | Description | Access | Quality |
| ------ | ----------- | ------ | ------- |
| | | | |
## Tasks
- [ ] Define problem statement and success metrics
- [ ] Identify and audit data sources
- [ ] Exploratory data analysis
- [ ] Feature engineering
- [ ] Model development
- [ ] Validation and testing
- [ ] Write-up and presentation
## Findings
## Decisions
Secret mission
Automated Weekly Review
Your command center surfaces today's priorities. But what about the projects that quietly slip through the cracks? In this secret mission, you'll build an automated weekly review that catches stalled experiments and overdue tasks before they snowball.
Clean Up Your Resources
Clean Up Your Resources
All resources in this project are local files stored inside your Obsidian vault with zero ongoing cost. There are no cloud services, no subscriptions, and nothing that charges money while sitting idle.
Resources you used:
- Style Settings Maison preset (stored in Obsidian plugin settings).
- CSS snippet file (maison.css, local file in .obsidian/snippets/).
- Template files (DS Project.md and Weekly Review.md, local markdown files).
- QuickAdd plugin and macro configuration.
- Archive/Weekly Reviews/ folder.
- Rebuilt Home.md dashboard.
Keep everything running
No action needed. Choose this if you are still actively using your Maison-styled vault and want everything to stay exactly as it is.
- Your vault will continue to open to the Maison Command Center dashboard.
- The QuickAdd hotkey remains active for instant project creation.
- Weekly reviews will continue to generate automatically when you click a week in the Calendar sidebar.
- The disabled theme-maison.css file remains in your snippets folder as a backup. You can delete it anytime if you no longer need it.
Pause - I'll come back to this later
Disable the visual customisations while keeping all files in place. This lets you return to default Baseline styling without losing any work.
- Open Settings > Appearance > CSS snippets and toggle OFF maison.css.
- Open Settings > Style Settings and click the reset icon to clear the Maison preset values.
- Re-enable theme-maison.css if you want your previous patchwork styling back temporarily.
- All template files, the QuickAdd macro, and your dashboard code remain untouched. Toggle maison.css back ON and re-import the preset to restore everything.
Delete - I don't want to use this again
Remove all project resources and revert your vault to its pre-project state.
- Open Settings > Appearance > CSS snippets. Toggle OFF maison.css, then click the folder icon to open the snippets folder. Delete the maison.css file.
- Open Settings > Style Settings and click the reset icon to clear all Maison preset values.
- Re-enable theme-maison.css in Settings > Appearance > CSS snippets to restore your previous styling.
- Delete Templates/Project Template/DS Project.md by right-clicking it in the file explorer and selecting Delete file.
- Delete Templates/Periodic/Weekly Review.md the same way.
- Delete the Archive/Weekly Reviews/ folder by right-clicking it and selecting Delete folder.
- Open Settings > Community plugins. Find QuickAdd in the list, click on it, then click Uninstall.
- Open Home.md and replace the dataviewjs block with your previous dashboard content (or delete all content below the frontmatter to start fresh).
- Open Settings > Hotkeys and search for QuickAdd. Remove the Cmd+Shift+N binding if it still appears.
Nice Work!
Nice Work!
You just transformed a patchwork Obsidian vault into a cohesive, automated command center for data science. Every surface now speaks the same visual language, your dashboard updates itself, and spinning up a new project takes a single keystroke.
Here's what you accomplished:
- Designed and applied a unified Maison design system across the entire vault using a Style Settings JSON preset and a single CSS snippet.
- Built an auto-updating dashboard that surfaces active projects with progress indicators, your highest-priority task, and today's agenda using Dataview.
- Created a one-hotkey project creation workflow using QuickAdd and Templater that generates consistent data science project structures.
- Secret Mission: Automated a weekly review system that catches stalled experiments and overdue tasks from the past 7 days.
Ready to quiz yourself?