Workflow Rituals¶
:pa recognises five trigger phrases and runs the corresponding playbook. You don't have to use these exact words — anything close enough works — but the explicit triggers are predictable.
standup (or morning)¶
When you start a session and today.md is empty, or you say standup explicitly, the AI:
- Reads the current week plan, today.md (if any), recurring ops, and your open OpenProject work packages
- Proposes a 3–7 item stack ordered by priority. Each item: WP ID, subject, one-phrase rationale ("in this week's focus", "blocking ACME release", "carryover from yesterday")
- Waits for your confirm
- On accept, writes
.bnerd/pa/scheduling/today.md
Example:
You: morning
bnerd (chief-of-staff):
Today's stack — confirm or edit:
- #7695 Test ticket — carryover from yesterday
- #7821 Migrate observability for ACME — in this week's focus
- #7902 Rotate gitlab-runner certs — recurring Tuesday duty
- #7950 Review monitoring dashboards (Verena) — team support
Write today.md? [y/n]
done (or done — short note)¶
The core walking-through-the-day flow. When you say done:
- The AI identifies the top unchecked item
- Calls
op_timer_status— if a pickup timer is running for this WP it stops it (using the elapsed time as the logged hours). Otherwise it asks you for hours. - If you supplied a one-liner ("done — fixed Squid TLS"), drafts a short audit-quality WP comment from it
- Single confirmation: "Close #1234, log 0.75h, post comment '…'?"
- On accept, fires:
op_timer_stoporop_log_time(whichever applies, depending on step 2)op_update_work_package(status → closed)op_add_comment(only if you gave a one-liner)mission_propose_today(with this item ticked)
- Surfaces the next: "Next: #5678 — Migrate observability for ACME. Pick it up?" — and on accept, calls
op_timer_startfor it.
The free-text fields auto-tag via bnerd.ai; the close + log are recorded in ~/.bnerd/openproject-audit.jsonl.
Pickup timers¶
:pa wraps OpenProject's native ongoing time entries via three tools:
op_timer_start work_package=… project=…— creates a running OP time entry. Visible in the OP web UI from this moment.op_timer_stop— finalises it: computes elapsed fromstartTime → now, PATCHesongoing=falseplushours. Returns the finalised entry as JSON.op_timer_status— reads the active timer (or returns{"active": false}).
Single timer per user — starting a second one returns a structured error so nothing is overwritten silently. None of the three are confirm-gated; they're high-frequency interactions you trigger explicitly. If op_timer_stop sees an elapsed of less than a minute or more than 24 hours it refuses; pass hours=<decimal> to override the elapsed calculation and finalise anyway. The same override also dismisses a stuck timer whose startTime is corrupt or empty.
Because state lives in OpenProject, killing :pa mid-task is fine: next session, op_timer_status shows the same running entry (with the real elapsed since you started).
Example:
You: done — fixed Squid TLS, verified end-to-end with curl
bnerd:
7695 — close + log 0.75h + comment:¶
Resolved: Squid TLS configuration corrected; curl end-to-end verification passed.
— via bnerd.ai
Confirm? [y/n]
replan (or replan, fire just came in for ACME)¶
When priorities shift mid-day:
- AI re-reads OpenProject for what changed since today.md was written
- Considers the new context you gave it
- Proposes a rewritten unchecked tail — preserving every checked item above the cursor
- Single confirm → today.md is rewritten in place
The checked entries are facts and are never touched. You can replan as many times per day as you want; the time you've already logged is in OpenProject and survives any re-plan.
debrief (or eod)¶
End of day:
- Summarises today: closed N WPs (list), logged X hours, deferred Y to tomorrow (list)
- Mentions any unread notifications worth following up on
- If today's date doesn't match what's in today.md, calling
mission_propose_todaywith the new date auto-archives yesterday's stack to.bnerd/pa/scheduling/archive/YYYY-MM-DD.md
weekly (or monday)¶
Once a week — usually Monday — the orchestrator runs:
- AI reads team capacity (
mission_team), active deployments (mission_deployments), recurring ops, the strategic ROADMAP, decisions accepted in the last 14 days, and last week's archived plan - Proposes
current.mdfor the new week with one focus item per team member or workstream + a risks list - Single confirm →
mission_propose_week(auto-archives the prior week)
current.md is a markdown+YAML document at .bnerd/pa/scheduling/current.md; you can edit it by hand any time, the AI honours edits.
triage slack (optional)¶
When the Slack integration is enabled, you can hand the inbox to the AI:
- Type
triage slack,process my inbox, or "what's in my slack" - AI calls
slack_inbox_list, fetches context for substantive items viaslack_get_thread, and either drafts replies (slack_propose_reply→ preview →slack_send_replywith one final confirm) or proposes tickets (pa_propose_ticketwith the thread excerpt as the description body) - From
:pa, therhotkey drafts a reply to the most-recent inbox event;tturns the latest thread into a ticket
If Slack isn't configured the tools error with a clear "not configured" message — the AI won't pretend they exist.
Ad-hoc mission edits (no ritual required)¶
Outside the rituals above you can ask :pa to update mission-repo files directly: bump a team member's capacity, draft a new decisions/ ADR, refresh a client brief, add an entry to ops/recurring.md, or sketch a new section in ROADMAP.md. The assistant uses mission_patch_file for surgical edits (preferred — only the changed lines move) and mission_write_file for new files or full rewrites. Both tools are sandboxed: paths are rejected if they resolve outside the mission repo, and today.md / current.md remain reserved for the typed mission_propose_* tools so their schema and auto-archive logic stay intact.
Every edit is confirm-gated, so even instructions like "just update Tobias's capacity to 36" still get a single integrity prompt before the file changes on disk.
Aren't these just prompts?¶
Yes. The rituals are encoded in the :pa system prompt — there's no special state machine in code. That's deliberate: the playbook is in plain language, you can override it ("forget the standup, just answer this"), and refining the rituals is a markdown edit, not a code change.
The system prompt is at pkg/ai/chat/prompt_pa.md.