AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Notion Briefs

skill-rhdeck-operating-model-notion-briefs · by rhdeck

Set up (or repair) the cross-project Notion "Briefs" system in a new environment — install the publisher CLI globally, solicit a Notion integration key, attach to a user-chosen Notion page, create an inline Briefs database, and register the tool in the global CLAUDE.md so every project can publish briefs/shift reports to one shared, newest-first database. Use when the user says "set up Notion bri…

No reviews yet
0 installs
37 views
0.0% view→install

Install

$ agentstack add skill-rhdeck-operating-model-notion-briefs

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-rhdeck-operating-model-notion-briefs)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Notion Briefs? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Notion Briefs — setup

This skill installs a cross-project brief/shift-report publisher backed by a single Notion database, and wires it into the environment so any project's agent can use it. It is portable: run it once per machine/environment the user works in. The end state mirrors the reference setup — an inline "Briefs" table living on a Notion page the user owns, fed by a project-neutral CLI.

The CLI and a README ship inside this skill (notion_briefs.py, README.md) — they are the source of truth; the install step copies them out to a global location.

What you will end up with

  • ~/.config/ai-briefs/notion_briefs.py — the publisher (stdlib only, no pip deps)
  • ~/.config/ai-briefs/token — the Notion integration secret (chmod 600)
  • ~/.config/ai-briefs/config.json{"briefs_db": ""}, written by bootstrap
  • A "Briefs" inline database on a Notion page the user picks (props: Name, Date, Type, Status, and a Project Overview relation added by bootstrap-projects)
  • A pointer block in the global ~/.claude/CLAUDE.md so every project discovers the tool

Idempotency — check before you act

Before doing anything, check what already exists and only fill gaps:

ls -la ~/.config/ai-briefs/ 2>/dev/null
cat ~/.config/ai-briefs/config.json 2>/dev/null   # has briefs_db? → DB already bootstrapped
test -s ~/.config/ai-briefs/token && echo "token present" || echo "need token"
grep -q "ai-briefs/notion_briefs.py" ~/.claude/CLAUDE.md && echo "CLAUDE.md pointer present" || echo "need CLAUDE.md pointer"

If everything is present and notion_briefs.py list works, there's nothing to do — report that and stop. Otherwise do only the missing steps.

Step 1 — Install the CLI globally

Copy the bundled files out of the skill to the global config dir (this dir is intentionally not tied to any repo, so every project shares it):

mkdir -p ~/.config/ai-briefs
cp "/notion_briefs.py" ~/.config/ai-briefs/notion_briefs.py
cp "/README.md"        ~/.config/ai-briefs/README.md
chmod +x ~/.config/ai-briefs/notion_briefs.py

(` is this skill's own directory — the same folder this SKILL.md` lives in.)

Step 2 — Get a Notion integration key (solicit from the user)

Talking to Notion's API requires an internal integration (a Notion "application") and its secret token. If ~/.config/ai-briefs/token is missing or empty, walk the user through creating one — do not invent or guess a key:

> To let me publish into Notion, I need an integration key. Please: > 1. Go to https://www.notion.so/my-integrationsNew integration. > 2. Pick Internal integration, name it (e.g. "AI Briefs"), select your workspace, and submit. > 3. Copy the Internal Integration Secret (starts with ntn_… or secret_…) and paste it here.

When the user provides it, write it to a file (never leave it only in chat; tell them they can rotate it later):

umask 077
printf '%s' '' > ~/.config/ai-briefs/token
chmod 600 ~/.config/ai-briefs/token

Validate it before continuing:

curl -s https://api.notion.com/v1/users/me \
  -H "Authorization: Bearer $(cat ~/.config/ai-briefs/token)" \
  -H "Notion-Version: 2022-06-28" | head -c 300

A valid key returns a bot user object; an error means the key is wrong — re-solicit.

Step 3 — Solicit the target page URL (different per environment — NEVER assume)

The page is environment/client-specific. Do not reuse a UUID from another setup or hardcode the reference workspace's page. Always ask the user for the URL of the page in this workspace that the Briefs table should live on.

> Where should the Briefs table live? In Notion: > 1. Create (or pick) a page you own — e.g. call it "AI Briefs". > 2. Open it → ••• (top-right) → Connections → add your integration (the one whose key you gave me). This is mandatory — Notion only lets an integration see pages explicitly connected to it, and it cannot be scripted. > 3. Copy the page URL (Share → Copy link) and paste it here.

Verify the integration can actually see that page before bootstrapping (catches the "forgot to connect" case):

PAGE_ID=$(python3 -c "import re,sys;print(re.search(r'[0-9a-fA-F]{32}', sys.argv[1].replace('-','')).group())" '')
curl -s "https://api.notion.com/v1/pages/$PAGE_ID" \
  -H "Authorization: Bearer $(cat ~/.config/ai-briefs/token)" \
  -H "Notion-Version: 2022-06-28" | head -c 300

If it returns object_not_found, the integration isn't connected to the page yet — ask the user to do the Connections step, then retry. Do not proceed past this gate.

Step 4 — Bootstrap the inline database

python3 ~/.config/ai-briefs/notion_briefs.py bootstrap --parent ''
# then create the Project Overviews DB + link it to Briefs (publish now REQUIRES this):
python3 ~/.config/ai-briefs/notion_briefs.py bootstrap-projects

The first command creates the "Briefs" database inline (a live table on the page), saves its id to config.json, and prints the database URL. Properties: Name · Date · Type (Brief / Shift Report / Plan — two distinct lifecycles share this DB, so the type matters) · Status (In Progress / Ready / Superseded / Done — the brief lifecycle, see README) · Project Overview (a relation to the Project Overviews DB, added by bootstrap-projects; the legacy free-text Project select has been retired). New Type/Status names and Project Overview pages auto-register on write, so new projects need no schema change. bootstrap-projects is requiredpublish hard-fails without a configured projects_db.

Tell the user two UI-only tweaks they may want (the API can't set view sort/filter): set the table's default Sort → Date, Descending so newest floats to top, and add per-project filtered views as they accumulate.

Step 5 — Register the tool in the global CLAUDE.md

So every project's agent discovers the tool without being told, ensure ~/.claude/CLAUDE.md contains a pointer. If the grep in the idempotency check showed it missing, append this section:

## Briefs & shift reports go to Notion (cross-project)

Briefs, shift reports, and plans for **any** project publish to one shared Notion "Briefs" database via the project-neutral CLI at **`~/.config/ai-briefs/notion_briefs.py`** (see that dir's `README.md`). One database, newest-first, tagged by `--project`; new project names auto-register, so this works the same from every repo without per-project setup. Prefer this over leaving a local `test-plans/*.md` brief. Publish at the end of a graveyard shift or a substantive session, then hand me the page URL — that page becomes where we iterate on the brief. The token lives in `~/.config/ai-briefs/token` (never paste it in chat). **If the tool isn't configured here** (no token / no `config.json`), run the **notion-briefs** setup skill — solicit a Notion integration key and the target page URL first.

Step 6 — Verify end-to-end

Prove the chain before declaring done — don't hand back an unverified setup:

# publish a tiny smoke-test brief, then confirm it lists, then optionally delete it in the UI
printf '# Setup smoke test\n\nNotion Briefs configured in this environment.\n' > /tmp/brief-smoke.md
python3 ~/.config/ai-briefs/notion_briefs.py publish \
  --project "Setup" --date "$(date +%F)" --title "Setup smoke test" \
  --type Brief --status Ready --file /tmp/brief-smoke.md
python3 ~/.config/ai-briefs/notion_briefs.py list

Hand the user the database/page URL and tell them the smoke-test row is safe to delete. If date isn't desirable, pass an explicit --date YYYY-MM-DD.

Daily use (after setup)

python3 ~/.config/ai-briefs/notion_briefs.py projects        # check the project pick-list first
python3 ~/.config/ai-briefs/notion_briefs.py publish \
  --project "" --date YYYY-MM-DD --title "Shift Report YYYY-MM-DD" \
  --type "Shift Report" --status "In Progress" --file report.md   # at shift START; prints the page URL
python3 ~/.config/ai-briefs/notion_briefs.py list [--project ""] [--status Ready]    # newest-first
python3 ~/.config/ai-briefs/notion_briefs.py append  --file closeout.md --divider        # "what we did" footer
python3 ~/.config/ai-briefs/notion_briefs.py set-status  --status Superseded              # retire: replaced / graduated
python3 ~/.config/ai-briefs/notion_briefs.py set-status  --status Done                    # retire: genuinely finished

--type is required on every publishBrief (a durable, multi-shift strategy/topic doc that gets decomposed into a GitHub epic, then retires) vs Shift Report (a per-shift execution record) vs Plan. An untyped row hides the distinction and is a bug.

Structure every report decisions-first. The reader opens it to answer "what needs a call from me?" — so the open 🟥/🟢 decisions go at the very TOP, above the fold, before any shipped-log or status recap. Never bury a decision below done-work. Full rule in README.mdStructure: lead with the decisions.

The brief is a living lifecycle object with four states: In Progress → Ready → (Superseded | Done). At a shift START, flip the prior shift report Ready → Superseded and create the new report In Progress (the plan); at shift END flip In Progress → Ready. A report stuck In Progress = a shift that may have died — a signal to pick it back up. When retiring, choose by where the work went: Superseded = replaced by a newer doc OR a Brief that graduated into a tracked epic (the work lives on elsewhere); Done = genuinely finished, nothing carried forward. The graveyard-shift skill drives the boundary transitions; the shift-change skill closes out. Full lifecycle + Type taxonomy in README.md.

> One brief needing attention per project — the listing points, it does not archive. The "needs your eyes now" state (Ready — the canonical review-awaiting status for both briefs and shift reports) is not a bucket of every live document; it is a pointer to the single brief you want the user's attention on right now. This is the listing's core job. Whenever you publish a brief that becomes the current decision surface, retire the prior one in the same breath (Superseded if its work lives on elsewhere, Done if finished). Whenever an older brief's conclusions have already been captured elsewhere (a newer brief, the Project Overview, or GitHub issues), retire it — its job is done. Before ending any turn that touched briefs, run list --status Ready --project "" and confirm exactly one thing is asking for attention. A listing with several attention-state rows is a failure, not thoroughness: it makes the user hunt for the decision instead of being handed it. If two genuinely compete, that is a signal to merge them into one decision-ready brief, not to leave both live.

GitHub auto-linking (publish + append)

Bare issue/PR refs like #308 in the markdown are auto-linked to GitHub so the user can click the number straight into the issue/PR — no manual linking needed. The repo is auto-detected from the cwd's git remote (so just run the publish from inside the project repo); override with --github-repo owner/repo if publishing from elsewhere. GitHub's /issues/ URL redirects to /pull/ for PRs, so issues and PRs both link correctly without distinguishing them. Refs inside ` backticks are left alone, and explicit [text](url) markdown links render as clickable links too. Write reports with plain #NNN` — the tooling handles the linking.

Notes / gotchas

  • Internal integrations cannot create workspace-level/root pages — the database must nest under an existing page the user shared with the integration (Step 3). That's why we solicit a page URL instead of making one.
  • The Connections step (Step 3.2) is the one thing that can't be scripted. Most setup failures are a forgotten connection — the page verify in Step 3 catches it.
  • Token hygiene: the secret lives only in ~/.config/ai-briefs/token (chmod 600). If it ever leaks into a transcript, the user can rotate it at notion.so/my-integrations and overwrite the file.
  • The CLI is stdlib-only (urllib + json) and honors a NOTION_TOKEN env override if set, else the token file.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.