Skip to content

Commit f272ace

Browse files
committed
added Slack functionality and template
1 parent b88c30f commit f272ace

4 files changed

Lines changed: 357 additions & 35 deletions

File tree

docs/runbook-weekly-summary.md

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ A short, human-readable summary of current org state:
1414

1515
The draft is written to `snapshot/weekly-summary.md` so review and Slack posting use the same text. `snapshot/` is gitignored, so this file is temporary working output.
1616

17+
For Slack posting, render that draft to `snapshot/weekly-summary.blocks.json` with Block Kit `rich_text_list` blocks so Slack shows real bullets instead of plain hyphen text.
18+
1719
Use `docs/templates/weekly-summary-template.md` for the message shape. Final approved summaries are archived in `docs/weekly-review-archive/` so future summaries can reference recent context.
1820

1921
Optionally posted to Slack. Always shown in the conversation first for review.
@@ -45,20 +47,22 @@ Always summarize from the fresh snapshot. The archive is useful context, not sou
4547

4648
### 3. Produce the summary draft
4749

48-
Write the summary to `snapshot/weekly-summary.md`, following `docs/templates/weekly-summary-template.md`. Use Slack-friendly `mrkdwn`: short headings, manual bullets, and plain text. Avoid tables and avoid composing the Slack message inline in a shell command.
50+
Write the summary to `snapshot/weekly-summary.md`, following `docs/templates/weekly-summary-template.md`. This markdown file is the human-review draft, the input to the Block Kit renderer, and the plain-text fallback. Use Slack-friendly `mrkdwn`: short headings, `-` markers with line breaks for list structure, and plain text. Avoid tables and avoid composing the Slack message inline in a shell command. Do not use `*` as a bullet marker in this text fallback; in Slack `mrkdwn`, `*text*` means bold.
51+
52+
For true Slack bullet rendering, render and post a Block Kit payload with `rich_text` / `rich_text_list` blocks. Incoming webhooks support `blocks`, and `tools/notify/post.sh` can send a rendered payload with `--payload`.
4953

50-
When naming issues, link only the issue number and put the title in plain text after it:
54+
When naming issues, put the issue title first, then link only the issue number:
5155

5256
```text
53-
<https://github.com/open-austin/org/issues/123|#123> Issue title
57+
Issue title | <https://github.com/open-austin/org/issues/123|#123>
5458
```
5559

5660
Do not use full-title links or standard Markdown links such as `[Issue title](https://...)`; Slack renders incoming webhook text more predictably with angle-bracket links.
5761

5862
The summary should cover:
5963

6064
**Teams with active issues:**
61-
List each team that has open issues. Use one parent bullet per team and one indented child bullet per issue. Add assignment details inline only when useful, such as `(assigned: lianilychee)`. Omit `Assigned: none`.
65+
List each team that has open issues. Use one parent bullet per team and one indented child bullet per issue. Include assignment status on every issue because unowned work is useful signal: `(assigned: none)` or `(assigned: lianilychee)`.
6266

6367
**Board state:**
6468
Org Kanban column counts. Put counts and issue lists on separate nested bullets so the Slack post does not become a dense paragraph. Flag anything that's been In Progress for a long time without update.
@@ -81,15 +85,35 @@ Show the contents of `snapshot/weekly-summary.md` in the conversation. Ask:
8185

8286
### 5. Post to Slack (if confirmed)
8387

88+
Render the reviewed markdown draft into a Slack Block Kit payload:
89+
90+
```bash
91+
tools/notify/render_weekly_summary_blocks.py snapshot/weekly-summary.md --output snapshot/weekly-summary.blocks.json
92+
```
93+
94+
Preview the payload without posting:
95+
96+
```bash
97+
tools/notify/post.sh SLACK_WEBHOOK_ORG --payload snapshot/weekly-summary.blocks.json --dry-run
98+
```
99+
100+
Then post the payload after approval:
101+
84102
```bash
85103
set -a
86104
source .env
87105
set +a
88-
tools/notify/post.sh SLACK_WEBHOOK_ORG < snapshot/weekly-summary.md
106+
tools/notify/post.sh SLACK_WEBHOOK_ORG --payload snapshot/weekly-summary.blocks.json
89107
```
90108

91109
For a general all-org channel, use the appropriate webhook variable from `.env`.
92110

111+
If Block Kit rendering fails, fall back to the plain-text message:
112+
113+
```bash
114+
tools/notify/post.sh SLACK_WEBHOOK_ORG < snapshot/weekly-summary.md
115+
```
116+
93117
If no Slack webhook is configured yet, just deliver the summary in the conversation.
94118

95119
### 6. Archive the final summary
@@ -124,6 +148,7 @@ This is manually triggered — no cron. Run it when the user asks. Once a week i
124148

125149
- `tools/sync/run.sh` — sync command
126150
- `tools/notify/post.sh` — Slack post command
151+
- `tools/notify/render_weekly_summary_blocks.py` — renders weekly summary markdown to Slack Block Kit JSON
127152
- `docs/templates/weekly-summary-template.md` — weekly summary template
128153
- `docs/weekly-review-archive/` — final weekly summary archive
129154
- `AGENTS.md` — agent rules and write safety

docs/templates/weekly-summary-template.md

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,42 +7,42 @@ Use this template when drafting `snapshot/weekly-summary.md` for the weekly org
77
88
*Active Issues by Team*
99
- *Finance* ({count}):
10-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title}
11-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title} (assigned: {names})
10+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: none)
11+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: {names})
1212
- *Fundraising* ({count}):
13-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title} (assigned: {names})
14-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title}
13+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: {names})
14+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: none)
1515
- *Communications* ({count}):
16-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title}
16+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: none)
1717
- *Engagement* ({count}):
18-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title} (assigned: {names})
18+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: {names})
1919
- *Education* ({count}):
20-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title}
21-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title}
22-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title}
20+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: none)
21+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: none)
22+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: none)
2323
- *Infrastructure* ({count}):
24-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title}
25-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title} (assigned: {names})
24+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: none)
25+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: {names})
2626
- *Community* ({count}):
27-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title}
27+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: none)
2828
- *Board* ({count}):
29-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title}
30-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title} (assigned: {names})
29+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: none)
30+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: {names})
3131
3232
*Board Health*
3333
- Org Kanban:
3434
- {done_count} Done
3535
- {in_progress_count} In Progress
3636
- {todo_count} To Do
3737
- In Progress:
38-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title} (assigned: {names}; stale {days}d)
39-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title} (assigned: {names}; stale {days}d)
38+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: {names}; stale {days}d)
39+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: {names}; stale {days}d)
4040
- Notable To Do:
41-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title}
42-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title}
41+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: {names or none})
42+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}> (assigned: {names or none})
4343
4444
*Needs Attention*
45-
- <https://github.com/open-austin/org/issues/{number}|#{number}> {Issue title}: {why it matters or what decision is needed}.
45+
- {Issue title} | <https://github.com/open-austin/org/issues/{number}|#{number}>: {why it matters or what decision is needed}.
4646
- {Brief blocker/staleness note, only if it needs human attention.}
4747
4848
*Summary*
@@ -51,12 +51,15 @@ Use this template when drafting `snapshot/weekly-summary.md` for the weekly org
5151

5252
## Style Rules
5353

54-
- Use Slack `mrkdwn` links, not standard Markdown links: `<https://github.com/open-austin/org/issues/123|#123> Issue title`.
55-
- Link only the issue number. Keep the issue title as plain text after the link.
54+
- Use Slack `mrkdwn` links, not standard Markdown links: `Issue title | <https://github.com/open-austin/org/issues/123|#123>`.
55+
- Put the issue title first as plain text, then link only the issue number.
5656
- Omit teams with no active in-scope issues.
57+
- This markdown is both the human-review draft and the input format for `tools/notify/render_weekly_summary_blocks.py`. Use `-` markers and two-space indentation consistently so the renderer can create Block Kit `rich_text_list` blocks.
58+
- In the plain-text fallback path, `-` markers plus line breaks mimic lists. Do not use `*` as bullets because `*text*` is Slack bold formatting.
59+
- For true Slack bullet rendering, post the rendered Block Kit payload with `tools/notify/post.sh SLACK_WEBHOOK_ORG --payload snapshot/weekly-summary.blocks.json`.
5760
- Use nested bullets so each issue gets its own line. Do not pack multiple issue links into one semicolon-separated sentence.
58-
- Keep issue metadata short and inline: `(assigned: name)` or `(assigned: name; stale 123d)`.
59-
- Omit empty/default metadata such as `Priority: none` and `Assigned: none`.
61+
- Keep assignment status on each issue because unowned work is useful signal: `(assigned: none)`, `(assigned: name)`, or `(assigned: name; stale 123d)`.
62+
- Omit empty/default priority metadata such as `Priority: none`.
6063
- Do not include Open Roles or recruiting tickets unless the user explicitly asks for them.
6164
- Do not include internal repo TODOs or tooling status unless they directly affect the org-facing work being summarized.
6265
- Keep Slack formatting simple: bold section headers, bullets, no tables.

tools/notify/post.sh

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,75 @@ set -euo pipefail
55
# Usage:
66
# tools/notify/post.sh <webhook_env_var> <message>
77
# cat message.txt | tools/notify/post.sh <webhook_env_var>
8+
# tools/notify/post.sh <webhook_env_var> --payload payload.json
9+
# tools/notify/post.sh <webhook_env_var> --payload payload.json --dry-run
810
#
911
# Example:
1012
# tools/notify/post.sh SLACK_WEBHOOK_ENGAGEMENT "Weekly summary text here"
1113
# echo "Hello" | tools/notify/post.sh SLACK_WEBHOOK_ENGAGEMENT
14+
# tools/notify/post.sh SLACK_WEBHOOK_ORG --payload snapshot/weekly-summary.blocks.json
1215
#
1316
# The webhook URL is read from the environment variable name you pass.
1417
# Load your .env first: source .env
1518

1619
WEBHOOK_VAR="${1:-}"
1720
MESSAGE="${2:-}"
21+
PAYLOAD_FILE=""
22+
DRY_RUN=false
1823

1924
if [ -z "$WEBHOOK_VAR" ]; then
2025
echo "Usage: tools/notify/post.sh <WEBHOOK_ENV_VAR> [message]" >&2
26+
echo " tools/notify/post.sh <WEBHOOK_ENV_VAR> --payload <payload.json>" >&2
27+
echo " Add --dry-run to print the payload without posting." >&2
2128
echo " Or pipe message via stdin." >&2
2229
exit 1
2330
fi
2431

25-
# Resolve the webhook URL from the env var name
26-
WEBHOOK_URL="${!WEBHOOK_VAR:-}"
27-
if [ -z "$WEBHOOK_URL" ]; then
28-
echo "Error: environment variable '$WEBHOOK_VAR' is not set." >&2
29-
echo "Did you source your .env file?" >&2
30-
exit 1
32+
if [ "$MESSAGE" = "--dry-run" ]; then
33+
DRY_RUN=true
34+
MESSAGE="${3:-}"
35+
fi
36+
37+
if [ "$MESSAGE" = "--payload" ]; then
38+
PAYLOAD_FILE="${3:-}"
39+
if [ -z "$PAYLOAD_FILE" ]; then
40+
echo "Error: --payload requires a JSON payload file." >&2
41+
exit 1
42+
fi
43+
if [ ! -f "$PAYLOAD_FILE" ]; then
44+
echo "Error: payload file not found: $PAYLOAD_FILE" >&2
45+
exit 1
46+
fi
47+
if [ "${4:-}" = "--dry-run" ]; then
48+
DRY_RUN=true
49+
fi
50+
fi
51+
52+
if [ -n "$PAYLOAD_FILE" ]; then
53+
jq -e 'type == "object" and (.text | type == "string")' "$PAYLOAD_FILE" >/dev/null
54+
55+
if [ "$DRY_RUN" = true ]; then
56+
cat "$PAYLOAD_FILE"
57+
echo "✓ Dry run: Slack payload rendered but not posted ($WEBHOOK_VAR)" >&2
58+
exit 0
59+
fi
60+
61+
# Resolve the webhook URL from the env var name
62+
WEBHOOK_URL="${!WEBHOOK_VAR:-}"
63+
if [ -z "$WEBHOOK_URL" ]; then
64+
echo "Error: environment variable '$WEBHOOK_VAR' is not set." >&2
65+
echo "Did you source your .env file?" >&2
66+
exit 1
67+
fi
68+
69+
curl -s -X POST "$WEBHOOK_URL" \
70+
-H 'Content-type: application/json' \
71+
--data-binary "@$PAYLOAD_FILE" \
72+
--fail
73+
74+
echo "" >&2
75+
echo "✓ Posted Slack payload ($WEBHOOK_VAR)" >&2
76+
exit 0
3177
fi
3278

3379
# Read message from arg or stdin
@@ -42,10 +88,25 @@ fi
4288

4389
# Escape for JSON
4490
ESCAPED=$(echo "$MESSAGE" | jq -Rs .)
91+
PAYLOAD="{\"text\": $ESCAPED}"
92+
93+
if [ "$DRY_RUN" = true ]; then
94+
echo "$PAYLOAD" | jq .
95+
echo "✓ Dry run: Slack text payload rendered but not posted ($WEBHOOK_VAR)" >&2
96+
exit 0
97+
fi
98+
99+
# Resolve the webhook URL from the env var name
100+
WEBHOOK_URL="${!WEBHOOK_VAR:-}"
101+
if [ -z "$WEBHOOK_URL" ]; then
102+
echo "Error: environment variable '$WEBHOOK_VAR' is not set." >&2
103+
echo "Did you source your .env file?" >&2
104+
exit 1
105+
fi
45106

46107
curl -s -X POST "$WEBHOOK_URL" \
47108
-H 'Content-type: application/json' \
48-
--data "{\"text\": $ESCAPED}" \
109+
--data "$PAYLOAD" \
49110
--fail
50111

51112
echo "" >&2

0 commit comments

Comments
 (0)