Skip to content

A runbook note kind: the steps of a procedure, each one copyable #76

Description

@vmillet-dev

A third NoteKind: an ordered list of steps where each one carries a body you can copy, not just a line of text.

A procedure has nowhere to live today. A snippet is parameterised but monolithic; a checklist is sequential but inert — its items are labels, and the command each one is about has to sit somewhere else. So the quarterly ritual that nobody remembers — rotating the staging certificates, resetting the local environment, cutting a release by hand — ends up in a NOTES.md nobody maintains, or in a Slack thread from last year.

Rotate the staging certificates        {{env=staging|prod}}  {{cluster}}

1. ▢  Point kubectl at the cluster
      kubectl config use-context {{cluster}}                        ⧉
2. ▢  Check the current expiry
      kubectl get secret tls-{{env}} -o json | step certificate …   ⧉
3. ▢  Trigger the renewal
      cert-manager renew tls-{{env}} -n {{env}}                     ⧉

It is the crossing of two features already built

Fill {{env}} and {{cluster}} once, at the top, and all six steps resolve. That is the whole point: a runbook is the snippet's parameters applied to the checklist's sequence, and neither feature alone reaches it.

The schema is already the right shape. note_items is (note_id, position, text, done), keyed on (note_id, position) so the position is the identity and a write rewrites the whole list. A step is that plus a body:

ALTER TABLE note_items ADD COLUMN body TEXT;
ALTER TABLE note_items ADD COLUMN language TEXT;

Two nullable columns, append-only, no default needed. A checklist item leaves both NULL. The pointer-drag reordering and its Alt+↑/↓ twin work unchanged.

copy_text absorbs the rest: it already carries the idea that a note knows what it copies, decided in Rust. A whole runbook copies as numbered Markdown with fenced blocks; a single step copies its resolved body. No rule crosses to the front end.

What has to be decided

  • Placeholders are note-wide, and that is not negotiable. placeholder::parse currently scans content; it has to scan step bodies too. A field asked per step would mean filling the same form six times — unusable, and it would make the feature pointless.
  • Does a step carry its own language? A runbook that mixes sh and sql wants per-step highlighting; one that does not wants to inherit the note's. The column above assumes per-step with a fallback, but it is a real choice.
  • What a ticked step means. A checklist's done is a state the user owns. A runbook's is closer to progress through one pass — which is the question A procedure can only be run once: no way to replay a checklist or a runbook #77 answers, and this ticket should not pre-empt it. Shipping with done behaving exactly as it does today is the honest first move.
  • Whether an empty-bodied step is legal. "Wait for the pipeline to go green" has nothing to copy. Probably yes, and the card simply shows no copy button.

Cost and traps

  • The three places that go wrong without a thought for the kind are already catalogued in CLAUDE.md, and a third kind exercises all three again: matches_search (which had to learn item texts for checklists — now it must learn bodies), transfer::to_markdown, and language detection. That the list is already written down is the sign the abstraction holds.
  • The card is the real cost, and it is interface, not Rust. A checklist card is two layers — the card button underneath, a sibling .card-items layer in pointer-events: none above it, with only the checkboxes taking pointer events back. A step now needs a checkbox and a copy button through that layer, and note-card.component.spec.ts asserts there is no <div> inside the card button.
  • transfer::Bundle deserialises Note itself, so the two new item fields need #[serde(default)] for the same reason kind and items do: an export written before runbooks must stay readable.
  • Do not reach for a second table. note_items with two nullable columns keeps one write path, one reorder path, one set of tests.

Done when: a procedure with six steps can be written once, filled once at the top, and followed by copying each step in turn — and copying the whole note into a ticket still produces readable Markdown.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions