Hugo Bases Skill

Create and edit Obsidian Bases (.base files) specifically designed for managing Hugo blog content. This skill extends standard bases functionality with Hugo-specific formulas, filters, and views.

Workflow

  1. Create the .base file in your content directory with Hugo-specific filters
  2. Define content scope using filters for posts, drafts, imported notes, etc.
  3. Add Hugo formulas for publishing status, content analysis, and import tracking
  4. Configure views for editorial dashboard, content planning, and import monitoring
  5. Validate that TOML frontmatter is properly parsed (requires YAML compatibility)
  6. Monitor content lifecycle from import to publication

Hugo-Specific Filters

Content Type Filters

filters:
  and:
    - 'file.ext == "md"'
    - file.inFolder("content")

# Only blog posts
filters:
  and:
    - file.inFolder("content/Postagens")
    - 'file.ext == "md"'

# Only imported notes
filters:
  and:
    - file.inFolder("content/notas")
    - 'file.ext == "md"'

# Drafts vs Published
filters:
  and:
    - 'draft == true'    # Only drafts
    # OR
    - 'draft != true'    # Only published

# By publication date
filters:
  and:
    - 'date > "2024-01-01"'
    - 'date < "2024-12-31"'

Import Status Filters

# Pending imports
filters:
  and:
    - file.inFolder("content/importando-vaults")

# Recently imported
filters:
  and:
    - file.inFolder("content/notas")
    - '(now() - file.mtime).days < 30'

Hugo-Specific Formulas

Publishing Status

formulas:
  status_publicacao: 'if(draft, "Rascunho", "Publicado")'

  # Import status tracking
  status_importacao: 'if(file.inFolder("content/importando-vaults"), "Pendente", if(file.inFolder("content/notas"), "Importado", "Nativo"))'

  # Days since publication
  dias_desde_publicacao: 'if(draft, "", (now() - date(date)).days)'

  # Content maturity
  maturidade: 'if(file.inFolder("content/Postagens"), "Blog Post", if(file.inFolder("content/notas"), "Nota", "Outro"))'

Content Analysis

formulas:
  # Reading time estimation (Portuguese average)
  tempo_leitura: '(file.size / 1000).round(0).toString() + " min"'

  # Word count estimation
  palavras_estimadas: '(file.size / 5).round(0)'

  # Content size in KB
  tamanho_kb: '(file.size / 1024).round(1)'

  # Age in days
  idade_conteudo: '(now() - file.ctime).days'

  # Last updated
  atualizado_recentemente: 'if((now() - file.mtime).days < 7, "Sim", "Não")'

SEO and Tags

formulas:
  # Tag count
  numero_tags: 'if(tags, tags.length, 0)'

  # Primary tag (first tag)
  tag_principal: 'if(tags && tags.length > 0, tags[0], "sem-tag")'

  # Has description for SEO
  tem_descricao: 'if(description, "Sim", "Não")'

  # Content quality score
  score_qualidade: 'numero_tags * 2 + if(description, 5, 0) + if(file.size > 2000, 3, 1)'

Import Tracking

formulas:
  # Pattern detection for imports
  padrao_origem: 'if(file.inFolder("content/importando-vaults"), if(file.basename.match(/^\d{4}-\d{2}-\d{2}/), "Diário", if(title.includes("INDEX") || title.includes("prompts"), "Pseudo-YAML", "Simples")), "Hugo Nativo")'

  # Priority for import
  prioridade_importacao: 'if(file.size > 2000, "Alta", if(file.size > 1000, "Média", "Baixa"))'

  # Conversion difficulty
  dificuldade_conversao: 'if(file.path.includes("wikilink") || file.path.includes("[["), "Complexa", "Simples")'

Date Formatting

formulas:
  # Format publication date
  data_formatada: 'if(date, date(date).format("DD/MM/YYYY"), "")'

  # Year for grouping
  ano_publicacao: 'if(date, date(date).year, "")'

  # Month for analysis
  mes_publicacao: 'if(date, date(date).format("YYYY-MM"), "")'

  # Day of week
  dia_semana: 'if(date, date(date).format("dddd"), "")'

Hugo Dashboard Examples

Editorial Dashboard

filters:
  and:
    - file.inFolder("content")
    - 'file.ext == "md"'

formulas:
  status_publicacao: 'if(draft, "Rascunho", "Publicado")'
  tempo_leitura: '(file.size / 1000).round(0).toString() + " min"'
  prioridade_edicao: 'if(draft && file.size > 1000, "Alta", if(draft, "Média", "Publicado"))'

views:
  - type: table
    name: "Rascunhos para Revisar"
    filters:
      and:
        - 'draft == true'
    order:
      - file.name
      - formula.tempo_leitura
      - formula.prioridade_edicao
      - file.mtime
    groupBy:
      property: formula.prioridade_edicao
      direction: DESC

  - type: table
    name: "Publicados Recentemente"
    filters:
      and:
        - 'draft != true'
        - '(now() - date(date)).days < 30'
    order:
      - date
      - file.name
      - formula.tempo_leitura

Import Monitoring Dashboard

filters:
  and:
    - 'file.ext == "md"'
    - file.inFolder("content")

formulas:
  status_importacao: 'if(file.inFolder("content/importando-vaults"), "Pendente", if(file.inFolder("content/notas"), "Importado", "Nativo"))'
  padrao_origem: 'if(file.inFolder("content/importando-vaults"), if(file.basename.match(/^\d{4}-\d{2}-\d{2}/), "Diário", "Texto"), "Hugo")'
  prioridade_importacao: 'if(file.size > 2000, "Alta", if(file.size > 1000, "Média", "Baixa"))'
  tamanho_kb: '(file.size / 1024).round(1)'

views:
  - type: table
    name: "Importações Pendentes"
    filters:
      and:
        - 'formula.status_importacao == "Pendente"'
    order:
      - formula.prioridade_importacao
      - file.name
      - formula.tamanho_kb
    groupBy:
      property: formula.padrao_origem
      direction: ASC
    summaries:
      formula.tamanho_kb: Sum

  - type: cards
    name: "Status Geral"
    order:
      - formula.status_importacao
      - file.name
      - formula.tamanho_kb
    groupBy:
      property: formula.status_importacao
      direction: ASC

Content Analysis Dashboard

filters:
  and:
    - file.inFolder("content/Postagens")
    - 'file.ext == "md"'

formulas:
  tempo_leitura: '(file.size / 1000).round(0)'
  numero_tags: 'if(tags, tags.length, 0)'
  ano_publicacao: 'if(date, date(date).year, "")'
  popularidade_estimada: 'numero_tags * tempo_leitura'

views:
  - type: table
    name: "Posts por Ano"
    order:
      - formula.ano_publicacao
      - date
      - file.name
      - formula.tempo_leitura
    groupBy:
      property: formula.ano_publicacao
      direction: DESC
    summaries:
      formula.tempo_leitura: Sum

  - type: table
    name: "Análise de Tags"
    order:
      - formula.numero_tags
      - file.name
      - formula.tempo_leitura
    summaries:
      formula.numero_tags: Average
      formula.tempo_leitura: Average

SEO Dashboard

filters:
  and:
    - file.inFolder("content/Postagens")
    - 'draft != true'

formulas:
  tem_descricao: 'if(description, "✅", "❌")'
  numero_tags: 'if(tags, tags.length, 0)'
  tamanho_adequado: 'if(file.size > 1500, "✅", "❌")'
  score_seo: 'if(description, 3, 0) + numero_tags + if(file.size > 1500, 2, 0)'

properties:
  formula.tem_descricao:
    displayName: "Descrição"
  formula.tamanho_adequado:
    displayName: "Tamanho OK"
  formula.score_seo:
    displayName: "Score SEO"

views:
  - type: table
    name: "SEO Check"
    order:
      - file.name
      - formula.tem_descricao
      - formula.numero_tags
      - formula.tamanho_adequado
      - formula.score_seo
    summaries:
      formula.score_seo: Average

Hugo-Specific Considerations

TOML vs YAML Compatibility

⚠️ Important: Obsidian Bases expect YAML frontmatter (---), but Hugo uses TOML (+++). For bases to read Hugo frontmatter properly:

  1. Convert key posts to YAML frontmatter for analysis
  2. Use file-based formulas (file.size, file.mtime) which always work
  3. Create separate analysis notes with YAML if needed for detailed property analysis

Working with Hugo Structure

# Target specific content types
filters:
  or:
    - file.inFolder("content/Postagens")    # Blog posts
    - file.inFolder("content/Portfólio")    # Portfolio
    - file.inFolder("content/notas")        # Imported notes

# Exclude build artifacts
filters:
  not:
    - file.inFolder("public")
    - file.inFolder(".hugo_build.lock")

Performance Tips

  • Limit scope to specific folders to improve performance
  • Use file-based formulas when possible (more reliable)
  • Cache results by saving base views as regular notes when needed

Integration with Import Workflow

Before Import

# Monitor pending imports
filters:
  and:
    - file.inFolder("content/importando-vaults")

formulas:
  estimated_work: 'if(file.size > 2000, "30 min", if(file.size > 1000, "15 min", "5 min"))'

After Import

# Track recent imports
filters:
  and:
    - file.inFolder("content/notas")
    - '(now() - file.mtime).days < 7'

formulas:
  needs_review: 'if(file.path.includes("wikilink"), "Sim", "Não")'

References