Skip to content

Feature: organize the KB with nested folders (hierarchical sections) #146

Description

@vikasiwp

The knowledge base is currently a strictly flat, two-level taxonomy — kb/<section>/<slug>.md — with no way to nest.

Current behavior (why nesting is impossible today)

KbStore.write() runs both section and slug through normSeg():

function normSeg(s: string): string {
  return String(s || "").toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
}

[^a-z0-9]+ -> "-" collapses any / to a hyphen, so section: "runbooks/infra" silently becomes the flat section runbooks-infra. rel_path is path.posix.join("kb", section, slug + ".md") and sections() returns a flat list — one folder level, full stop.

The problem (motivation)

A single section grows unwieldy fast. In one workspace the runbooks section already holds 15 pages mixing infra / migration / security / support (vs. 1 each for the other sections). There is no way to group runbooks/infra/*, runbooks/migration/*, runbooks/support/* — they all live as siblings in one flat runbooks/ bucket, which hurts both the console tree and human/git browsing of the on-disk mirror.

Proposal

Allow hierarchical sections (arbitrary, bounded depth):

  1. Path-aware section — permit / in section and normalize per segment (each segment still normSeg-clean), so runbooks/infrakb/runbooks/infra/<slug>.md. Reject .. and leading/trailing / (the on-disk mirror already guards containment via contained() — keep that as the security backstop against traversal).
  2. sections() returns a tree (or the console derives one by splitting on /) so the KB view can render nested folders.
  3. Search section filter becomes a prefix match (section = "runbooks" still returns everything under it; section = "runbooks/support" scopes to that subtree). FTS/rel_path/revisions are unaffected — only the section segmenting changes.

Backward compatibility

Existing flat pages are untouched (a single-segment section is just a depth-1 path). No migration needed; normSeg still applies to each segment, so url-safety and the 64-char cap per segment hold.

Nice-to-haves (out of scope, but enabled by this)

  • Console breadcrumb / collapsible tree per subtree.
  • Per-subtree ownership/tags conventions (e.g. runbooks/support/* owned by the support agent).

Happy to send a PR if this direction is acceptable.

🤖 Filed with Claude Code · https://claude.ai/code/session_01HiUDC14XfeTQJZHf2wswma

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions