# Store starter: Notion. `scripts/read_store.py` reads this file as the base layer; the project's # _bmad/custom/ticketing-store-config.toml names the store, fills the empty fields below, and replaces # any other key here, key by key. # It updates with the skill and holds only what is specific to this store: the rules every store shares # are in references/board.md. Comments and `description` are never loaded; `description` is for choosing a store. # # One tool: Notion's official MCP server. One database holds every ticket; properties carry type, # status, assignee, and hitl; two self-relations carry hierarchy (Parent) and blocking (Blocked by); # a board view grouped by Status is the kanban. `setup` creates all of it. description = "Notion through its MCP server: one tickets database with a board view, relations for hierarchy and blocking. For teams that plan in Notion and want tickets beside their docs." [tickets] store = "notion" key = "" # prefix of the database's ID property, e.g. "SHOP" gives SHOP-12; empty = page ids only database = "" # url or id of the tickets database; empty = `setup` creates it access = """ Use the Notion MCP (notion-fetch, notion-create-pages, notion-update-page, notion-query-data-sources, notion-create-comment, notion-get-users) against `database`. Confirm from the tool schema how relation and person properties are passed; `notion-get-users` resolves a name. An empty `database` means `setup` has not run. """ fields = """ risk and severity are select properties: Risk (low, medium, high) and Severity (P0-P3); `setup` creates them, publish and update set them. estimate is a text property Estimate, created with the rest. Empty field: property left empty. """ reference = """ Notion renders urls as links; a Notion page url becomes a mention. """ [verbs] setup = """ Connect, unless the Notion tools already answer: add the MCP server https://mcp.notion.com/mcp to the agent tool in use (in Claude Code, `claude mcp add --transport http notion https://mcp.notion.com/mcp`), then sign in over OAuth. Either way, share the database, or the page it will be created under, with the connection. When `database` is empty: ask which page to create under, then `notion-create-database` named Tickets with properties Title (title), Type (select, options per [tickets.types]), Status (status, options per [tickets.status]), Parent (relation to this database), Blocked by (relation to this database), Assignee (person), Covers (text), Risk (select: low, medium, high), Severity (select: P0, P1, P2, P3), Estimate (text), hitl (checkbox), and, when `key` is set, ID (unique id with that prefix). Then `notion-create-view`: a board grouped by Status. Give the user the url and put it in `database` in the project's store config. When `database` is set: `notion-fetch` it and compare its properties and options with the maps; add a missing option with `notion-update-data-source`, and tell the user about anything the schema needs a person to change. """ write = """ tracker_id is the ID property when `key` is set, else the page id; remote is the page url. `notion-create-pages` into `database` creates; `notion-update-page` changes any property or the content — Status, Assignee, Parent, Blocked by, Covers, Risk, Severity, hitl. Status is [tickets.status].. No parent: leave the Parent relation empty. An initiative is a page of Type initiative with no Parent. The body is the page content. """ query = """ One page: `notion-fetch` — Title, Type, Status, Assignee, Parent, Blocked by, Covers, Risk, Severity, hitl, and the content; after is Blocked by. Many: `notion-query-data-sources` on `database` filtered by any property; `notion-search` scoped to `database` for a looser match. """ # BMad type -> this store's type (Type select options; `setup` creates them). [tickets.types] initiative = "initiative" epic = "epic" story = "story" spike = "spike" bug = "bug" # BMad state -> this store's status (Status property options; `setup` creates them). [tickets.status] backlog = "Backlog" in-progress = "In Progress" review = "Review" done = "Done" dropped = "Dropped"