Skip to content

T-781K-add-obsidian-bases-setup-flag

Status: closed/done · Impact: medium · Complexity: small

Planning artifacts live as markdown under docs/planning/<plural>/, but there’s no built-in way to browse them in Obsidian as queryable tables. Obsidian’s Bases feature provides per-folder YAML query files (.base) that render frontmatter as tables. Adding --obsidian to /sdlc:setup lets users opt into Bases generation in one command, surfacing tasks/epics/milestones/backlog with curated columns without hand-authoring each .base file.

  • /sdlc:setup is driven by plugin/scripts/setup_planning.py, which iterates plugin/entities/<type>/schema.json and creates docs/planning/<plural>/ directories. It does not write .base files.
  • docs/Untitled.base and docs/Untitled 1.base are minimal stubs (views:\n - type: table\n name: Table) from manual experimentation — not generated, not in the canonical entity folders.
  • Each entity schema defines the frontmatter shape we’d want to render as columns: task.schema.json has status/impact/complexity/last_reviewed/readiness_verified_at; epic and milestone add target_date/version; backlog has status/tags/result.
  • Users who want Obsidian table views over their planning artifacts must hand-write each .base file and keep it in sync with schema changes by hand.
  • /sdlc:setup --obsidian generates one <plural>.base file in each docs/planning/<plural>/ directory (e.g. tasks.base in docs/planning/tasks/, backlog.base in docs/planning/backlog/backlog is already plural).
  • Each generated .base contains a single table view scoped to its own folder (via file.inFolder("docs/planning/<plural>")), with a column order curated per entity (status first, then triage/scheduling fields, then file name), grouped by status ASC so active stages cluster above closed/*.
  • Re-running --obsidian is idempotent: existing .base files are left untouched unless --force is also passed.
  • Per-entity column choices live alongside each schema as plugin/entities/<type>/base.yaml, keeping the entity directory the single source of truth (sibling to schema.json and template.md).
  • /sdlc:setup without --obsidian behaves exactly as today — no .base files written.
  1. Add a base.yaml template to each plugin/entities/<type>/ directory — committed as the canonical column set, group/sort, and filter for that entity. YAML so it’s directly emittable to <plural>.base (Bases files are pure YAML). Initial column sets:
    • task (tasks.base): columns status, impact, complexity, last_reviewed, readiness_verified_at, file.name. groupBy: { property: note.status, direction: ASC }. Filter file.inFolder("docs/planning/tasks").
    • epic (epics.base): columns status, target_date, last_reviewed, id, file.name. Group by status ASC.
    • milestone (milestones.base): columns status, version, target_date, last_reviewed, file.name. Sort by version DESC, then status.
    • backlog (backlog.base): columns status, tags, last_reviewed, result, file.name. Group by status ASC.
  2. Extend plugin/scripts/setup_planning.py: add --obsidian and --force flags. New helper function write_bases(entities_dir, planning_root, force, dry_run) that, for each entity, reads plugin/entities/<type>/base.yaml, resolves destination docs/planning/<plural>/<plural>.base, and writes (or skips with a “exists” report) per the idempotency rule. Reuse the existing pluralize() helper. Keep emission deterministic — copy the template bytes verbatim rather than parsing-and-re-emitting (avoids YAML key reorder churn).
  3. Update plugin/skills/setup/SKILL.md usage block to document --obsidian and --force, with a one-sentence pointer to Obsidian Bases (https://help.obsidian.md/bases). Keep the existing dry-run / audit behavior unchanged.
  4. Manually open one generated .base file (e.g. docs/planning/tasks/tasks.base) in Obsidian to confirm it loads as a table without YAML errors. Document the verification step in the PR.
  • plugin/entities/task/base.yaml (new) — task Bases template; status-first columns, group by status ASC, filter to docs/planning/tasks.
  • plugin/entities/epic/base.yaml (new) — epic Bases template.
  • plugin/entities/milestone/base.yaml (new) — milestone Bases template; sort by version DESC.
  • plugin/entities/backlog/base.yaml (new) — backlog Bases template.
  • plugin/scripts/setup_planning.py — add --obsidian and --force flags; add write_bases() helper; wire it into main() so it runs after directory creation when --obsidian is set.
  • plugin/skills/setup/SKILL.md — document the new flags in the Usage block and mention Bases briefly in Notes.
  • AC-1: Running /sdlc:setup --obsidian in a fresh project creates tasks.base, epics.base, milestones.base, and backlog.base in their respective docs/planning/<plural>/ directories.
  • AC-2: Each generated .base file is valid YAML, contains a single table view, and the columns referenced under views[0].order all map to either a real frontmatter field declared in that entity’s schema.json or a documented file.* / formula.* reference.
  • AC-3: Re-running /sdlc:setup --obsidian without --force leaves an existing .base file untouched (mtime unchanged); re-running with --force overwrites it from the template.
  • AC-4: Opening one generated .base file in Obsidian renders the corresponding planning artifacts as a table without “invalid base” errors (manual verification, noted in PR).
  • AC-5: /sdlc:setup without --obsidian writes zero .base files — directory-creation behavior is byte-for-byte unchanged.
  • AC-6: /sdlc:setup --obsidian --dry-run reports what .base files would be written without touching the filesystem.
  • View types beyond table (card, gallery, kanban). table only for v1.
  • Cross-entity views (e.g. one base showing all open work across tasks + epics + milestones).
  • Formulas (e.g. days_since_last_reviewed). Can be added once the basic table views are validated in the wild.
  • An inverse flag to delete previously-generated .base files.
  • Auto-regenerating .base files when an entity schema changes. The user re-runs with --force.
  • none

<Optional. How this task got onto the list: linked incident, design doc, upstream conversation, prior PR review comment. Helps future-you remember why this was worth doing. Delete this section if there’s nothing to add.>

Captured by /sdlc:task-work on 2026-05-20. PR: pending.

  • AC-1: agent-manual — ran setup_planning.py --obsidian in a fresh tmp dir; find docs -name "*.base" produced docs/planning/{tasks/tasks,epics/epics,milestones/milestones,backlog/backlog}.base.
  • AC-2: auto — Python yaml.safe_load parsed each plugin/entities/<type>/base.yaml, asserted views[0].type == 'table' and that order was a non-empty list; printed the order for inspection.
  • AC-3: agent-manual — captured mtime of tasks.base (1779240251), re-ran without --force (mtime unchanged), re-ran with --force (mtime 1779240258).
  • AC-4: auto — plugin/validators/validate_base.py (headless Obsidian Bases parser) validates each shipped plugin/entities/<type>/base.yaml; .claude/skills/project-check/check_entity_bases.py runs the validator against every template as part of /project-check. Originally deferred-user because Obsidian itself surfaces “invalid base” errors only at render time; reclassified to auto by T-6ZNY-headless-bases-syntax-parser-for-eval.
  • AC-5: agent-manual — ran setup_planning.py (no flags) in a separate fresh tmp dir; find docs -name "*.base" produced no output.
  • AC-6: agent-manual — setup_planning.py --obsidian --dry-run reported the four would write: lines; find docs -type f after dry-run was empty.
  • The “copy template bytes verbatim” rule from the task spec eliminated all YAML-emit churn; mtime-based idempotency just works.
  • Pre-shipping base.yaml per entity (sibling to schema.json) keeps Bases column choices co-located with the schema they reference — easy to keep in sync.
  • The pre-existing pluralize() drift on backlog was caught immediately by the first dry-run and isolated to a one-line conditional in write_bases without touching pluralize().
  • just setup-worktree failed (no justfile in this repo) — task-work’s Step 4 init was a no-op fallback. The existing backlog task 2026-05-19-task-work-graceful-no-justfile-fallback (and the broader task-work-uses-per-project-quality-checks) already cover this gap. → T-FC8W-task-work-graceful-no-justfile-fallback
  • Pre-existing backlog vs backlogs directory inconsistency surfaced again: pluralize("backlog") produces backlogs but real backlog content lives in docs/planning/backlog/. Worked around in write_bases with a hardcoded carve-out; root fix would require either (a) making pluralize() recognize backlog as already plural (changes AC-5’s invariant), or (b) renaming the entity dir from backlog/ to backlogitem/ (heavier). Worth its own follow-up. → T-5BAR-pluralize-recognizes-backlog-as-plural
  • AC-2 was verifiable by a Python one-liner but not by any committed test — a plugin/entities/*/base.yaml shape check would prevent silent drift if the templates evolve. Worth a small lint/validator follow-up. → T-DIMU-lint-entity-base-yaml-templates
  • AC-4 was structurally a deferred-user check because Obsidian isn’t headless; an eval pattern that loads a .base through a minimal Bases-syntax parser closes the loop. Resolved by T-6ZNY-headless-bases-syntax-parser-for-eval (validator at plugin/validators/validate_base.py, project-check wiring at .claude/skills/project-check/check_entity_bases.py). → T-6ZNY-headless-bases-syntax-parser-for-eval

← Back to Tasks