用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/CodySwannGT/lisa --skill lisa-setup-notion命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
This skill should be used for any non-trivial request — features, bugs, stories, epics, spikes, or multi-step tasks. It accepts a ticket URL (Jira, Linear, GitHub), a file path containing a spec, or a plain-text prompt. It assembles an agent team, breaks the work into structured tasks, and manages the full lifecycle from research through implementation, code review, deploy, and empirical verification.
any non-trivial request —…
This skill should be used for any non-trivial request — features, bugs, stories, epics, spikes, or multi-step tasks. It accepts a ticket URL (Jira, Linear, GitHub), a file path containing a spec, or a plain-text prompt. It assembles an agent team, breaks the work into structured tasks, and manages the full lifecycle from research through implementation, code review, deploy, and empirical verification.
正在显示 SKILL.md
| name | lisa-setup-notion |
| description | Configure Notion as the PRD… |
| allowed-tools | ["Bash","Read","Write","Edit","Skill","AskUserQuestion"] |
Provision Notion access for this project. After this skill runs, .lisa.config.json contains notion.workspaceId and notion.prdDatabaseId, and the OS keychain has a lisa-notion entry keyed by the workspaceId.
Ask via AskUserQuestion:
How do you want lisa to talk to Notion for this project?
- MCP-only (simplest) — authenticate the Notion MCP once via browser OAuth; lisa uses it for every operation. Best for: single-workspace developers on a personal laptop. New developers onboard with one OAuth flow, no token sharing, no rotation pain when someone leaves. Skip the rest of this setup.
- MCP + internal-integration token (recommended for teams) — MCP for interactive dev, internal-integration token in keychain for headless / CI / multi-workspace. Continue through token-create steps.
- Token-only (headless / CI) — store a workspace-scoped internal-integration token in the OS keychain; lisa uses curl for everything. Best for: CI pipelines, headless containers. Continue through token-create steps.
If the user picks (1) and the MCP is already authenticated to the right workspace (verify by attempting to fetch the configured prdDatabaseId via the MCP — success means identity match), write only notion.workspaceId, notion.prdDatabaseId, and notion.statusProperty into .lisa.config.json and skip to Step 8 (top-level source offer). If the MCP isn't authed yet, instruct the user to run mcp__claude_ai_Notion__authenticate (or the plugin equivalent) and complete the OAuth flow, then re-verify. The PRD database still needs to be shared with the OAuth-granted access — Notion's per-page sharing model applies to OAuth identities the same way it does to internal-integration tokens.
If the user picks (2) or (3), continue through the rest of the steps; the token gets stored in addition to (or instead of) the MCP session.
case "$(uname -s)" in
Darwin) open "https://www.notion.so/profile/integrations" ;;
Linux) xdg-open "https://www.notion.so/profile/integrations" 2>/dev/null ;;
MINGW*|MSYS*|CYGWIN*) start "https://www.notion.so/profile/integrations" ;;
esac
Print instructions for the user:
1. Click "New integration".
2. Name it: lisa-<project-name> (e.g., lisa-gemini, lisa-acme — pick something descriptive).
3. Associated workspace: pick the workspace your PRDs live in.
4. Type: "Internal integration".
5. Capabilities: leave defaults (Read content, Update content, Insert content). No comment / user-info capabilities needed.
6. Click Save.
7. On the integration's detail page, click "Show" next to "Internal Integration Token".
8. Copy the token — starts with `ntn_`. Atlassian-style scoped tokens have a `=<CRC>` suffix; Notion's do NOT, but tokens are still 50+ chars. Watch for clipboard-truncation in some terminals.
The user picks a stable identifier for this workspace. Two options:
AcmeOrgB). Easy to recognize, can be ambiguous if a workspace is renamed in Notion. Recommended.Default to the workspace name. After the user stores the token (Step 4), Step 5's /users/me call surfaces the actual bot.workspace_name; if it differs from what the user typed (capitalization, trailing whitespace), prompt to confirm.
WORKSPACE=$(jq -r '.notion.workspaceId // empty' .lisa.config.json 2>/dev/null)
if [ -z "$WORKSPACE" ]; then
# Prompt the user — accept any non-empty string. They pick the slug; we just store it.
read -p "Workspace identifier (any stable slug, e.g. 'acme-org-b'): " WORKSPACE
fi
This is non-optional. Notion's permission model is share-based — the integration cannot see any pages or databases until the user explicitly grants access.
Print instructions:
1. In Notion, navigate to your PRD database (or the parent page containing it).
2. Click the "..." menu in the top right of the database.
3. Click "Connections".
4. Find "lisa-<project>" in the list and click "Connect".
5. Confirm any prompts about granting access.
The connection cascades to all child pages of the database by default. New PRDs added under the database automatically inherit access.
If --database=<uuid> was passed in $ARGUMENTS, use it; otherwise prompt:
DATABASE_ID=$(jq -r '.notion.prdDatabaseId // empty' .lisa.config.json 2>/dev/null)
if [ -z "$DATABASE_ID" ]; then
cat <<EOF
Paste the PRD database URL or ID:
- URL form: https://notion.so/<workspace>/<database-id>?v=...
- ID form: 32-char UUID with or without dashes
EOF
read -p "Database: " DB_INPUT
# Extract UUID from URL if needed.
DATABASE_ID=$(echo "$DB_INPUT" | grep -oE '[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}' | head -1)
if [ -z "$DATABASE_ID" ]; then
echo "Error: could not extract a UUID from '$DB_INPUT'." >&2
exit 1
fi
fi
Same security posture as setup-atlassian. Print a platform-specific clipboard-pipe command for the user to run in their own terminal:
case "$(uname -s)" in
Darwin)
cat <<EOF
1. Copy the integration token from the Notion page.
2. Run this single line in your terminal (leading space keeps it out of zsh history):
security delete-generic-password -s lisa-notion -a "$WORKSPACE" 2>/dev/null; TOK="\$(pbpaste)"; security add-generic-password -U -s lisa-notion -a "$WORKSPACE" -w "\$TOK"; unset TOK
The token is piped from clipboard straight to keychain — never enters the prompt or chat.
EOF
;;
Linux)
if command -v secret-tool >/dev/null 2>&1; then
if command -v wl-paste >/dev/null 2>&1; then CLIP=wl-paste
elif command -v xclip >/dev/null 2>&1; then CLIP="xclip -selection clipboard -o"
elif command -v xsel >/dev/null 2>&1; then CLIP="xsel --clipboard --output"
else CLIP="cat"
fi
cat <<EOF
1. Copy the integration token.
2. Run this in your terminal:
secret-tool clear service lisa-notion account "$WORKSPACE" 2>/dev/null; printf '%s' "\$($CLIP)" | secret-tool store --label="Lisa Notion ($WORKSPACE)" service lisa-notion account "$WORKSPACE"
(If no clipboard tool is installed: the command reads from stdin — paste, Ctrl-D.)
EOF
else
cat <<EOF
libsecret / secret-tool not installed. Options:
1. Install: sudo apt install libsecret-tools (then re-run /lisa:setup:notion).
2. Env-var fallback (headless / CI / Docker):
export NOTION_API_TOKEN_$(echo "$WORKSPACE" | tr '[:upper:]-' '[:lower:]_')="<paste-token>"
Plaintext on disk — only acceptable on ephemeral / CI environments.
EOF
fi
;;
MINGW*|MSYS*|CYGWIN*)
cat <<EOF
PowerShell:
\$tok = Get-Clipboard; cmdkey /generic:"lisa-notion-$WORKSPACE" /user:"$WORKSPACE" /pass:"\$tok"; Remove-Variable tok
EOF
;;
Never accept the token via chat or stdin into this skill. Wait for the user to confirm storage.
Use the same lookup ladder notion-access uses:
read_notion_token() {
local workspace="$1"
[ -n "$NOTION_API_TOKEN" ] && { echo "$NOTION_API_TOKEN"; return; }
local slug=$(echo "$workspace" | tr '[:upper:]-' '[:lower:]_')
local varname="NOTION_API_TOKEN_${slug}"
[ -n "${!varname}" ] && { echo "${!varname}"; return; }
# Preferred path: the single secrets chokepoint. It owns the one-store rule
# and the surface ladder, so anything it can answer must not be read out of an
# OS keychain here — a second reader is how the same credential ends up living
# in two places and drifting. Keep the LADDER below identical to
# `notion-access`; the tail may differ, because this skill falls through to a
# legacy keychain rung and that one does not. Saying "the ladder" rather
# than "this function" is deliberate — the old wording asked for something
# unachievable, and an unachievable rule is one that gets quietly dropped.
#
# Ordered across trusted machine-managed substrates, ending at the installed
# package. Checkout-local paths are deliberately absent: a familiar generated
# destination is still repository-controlled executable code. The plugin
# rungs are the floor: `resolve-secret.mjs` ships beside this skill, so a rung
# pointing at it is reachable from anywhere the plugin itself is installed.
candidates=()
[ -n ];
candidates+=()
[ -n ];
candidates+=()
candidates+=(node_modules/@codyswann/lisa/plugins/lisa/skills/lisa-secrets-access/scripts/resolve-secret.mjs)
resolver
tried=()
resolver ;
tried+=()
[ -f ];
via_lisa
via_lisa=$(node get NOTION_API_TOKEN 2>/dev/null) \
&& [ -n ] && { ; ; }
from_keychain=
Darwin) from_keychain=$(security find-generic-password -s lisa-notion -a -w 2>/dev/null) ;;
Linux) -v secret-tool >/dev/null && \
from_keychain=$(secret-tool lookup service lisa-notion account 2>/dev/null) ;;
MINGW*|MSYS*|CYGWIN*)
from_keychain=$(LISA_CRED_TARGET= powershell.exe -NoProfile -NonInteractive -Command 2>/dev/null | -d ) ;;
[ -n ] && { ; ; }
>&2
>&2
>&2
>&2
1
}
TOKEN=$(read_notion_token )
[ -z ];
>&2
1
[ -lt 40 ];
>&2
ME=$(curl -s -H \
-H \
)
ME_WORKSPACE=$( | jq -r )
[ -z ];
>&2
1
[ != ];
<<
DB_PROBE=$(curl -s -o /tmp/setup-notion-db -w \
-H -H \
)
[ != ];
>&2 <<
1
Read the database schema and find the Status property's value list. Compare to lisa defaults and prompt for overrides if names differ.
DB_SCHEMA=$(curl -s -H "Authorization: Bearer $TOKEN" -H "Notion-Version: 2022-06-28" \
"https://api.notion.com/v1/databases/$DATABASE_ID")
STATUS_PROP=$(jq -r '.properties | to_entries[] | select(.value.type == "status" or .value.type == "select") | .key' <<<"$DB_SCHEMA" | head -1)
STATUS_VALUES=$(jq -r --arg p "$STATUS_PROP" '.properties[$p] | (.status.options // .select.options) | .[].name' <<<"$DB_SCHEMA")
For each lisa role (draft, ready, in_review, blocked, ticketed, shipped, verified), check if its default name (Draft, Ready, etc.; Verified for verified) appears in $STATUS_VALUES. If a role's default is missing but a similar-looking value exists, prompt the user to map it via AskUserQuestion. If a role has no plausible match, prompt to either create the value in Notion or accept that the lifecycle stage is unrepresented. This find-or-create-or-accept path is idempotent per role: a value already present (default or mapped) is reused untouched, so re-running never duplicates a status option.
verified is the terminal lifecycle state after shipped (the verified role from the config-resolution rule, #591): /lisa:verify-prd transitions a Notion PRD into it once the shipped product has been empirically verified against the PRD. Notion models the PRD lifecycle as Status (or select) property options rather than labels, so verified is mapped or created through the exact same path as every other role above — and, like them, persisted to notion.values.verified when the workspace uses a non-default option name.
Collect overrides as a partial values map. Only write keys that differ from defaults — verified included, so a non-default Verified option name lands in notion.values.verified.
.lisa.config.jsonjq --arg ws "$WORKSPACE" --arg db "$DATABASE_ID" --arg sp "$STATUS_PROP" --argjson values "$VALUES_JSON" '
.notion = ((.notion // {})
| .workspaceId = $ws
| .prdDatabaseId = $db
| (if $sp != "" then .statusProperty = $sp else . end)
| (if $values != {} then .values = $values else . end))
' .lisa.config.json > .lisa.config.json.tmp \
&& mv .lisa.config.json.tmp .lisa.config.json
VALUES_JSON is {} if all roles use the default names; otherwise contains only the overrides.
sourceIf .source is unset or differs from "notion", ask via AskUserQuestion:
Notion is configured. Set top-level
source: "notion"so/lisa:intake(with no args) scans this database for PRDs?
If yes:
jq '.source = "notion"' .lisa.config.json > .lisa.config.json.tmp \
&& mv .lisa.config.json.tmp .lisa.config.json
jq -e '.notion.workspaceId and .notion.prdDatabaseId' .lisa.config.json >/dev/null
echo "Token validated (${#TOKEN} chars). Workspace: $ME_WORKSPACE. Database: $DATABASE_ID."
Report success with the resolved workspace, database, status property name, and value overrides (if any), confirming all lifecycle roles — including the terminal verified — were detected, mapped, or flagged for creation. Direct the user to /lisa:intake to test.
notion section without disturbing others. The keychain entry update in Step 4 is the user's manual action — they re-run the same security / secret-tool / cmdkey command.notion.workspaceId and notion.prdDatabaseId already exist in config, skip the prompts in Steps 2–3 and go straight to verification..lisa.config.json. Tokens stay in keychain or env..lisa.config.local.json notion.workspaceId is the sole disambiguator. There is no "active workspace" concept on the Notion side — the token IS the workspace binding.