From forge
Reference skill for all Notion operations in forge — pushing brainstorms and plans to Notion pages, pulling Notion content as input, and live-updating pages during execution. Only active when .forge/config.json exists.
npx claudepluginhub ekelhaft-tools/forge-cursorThis skill uses the workspace's default tool permissions.
Bidirectional sync between forge sessions and Notion. Called by brainstorming, planning, and executing skills — never directly by the user.
Creates isolated Git worktrees for feature branches with prioritized directory selection, gitignore safety checks, auto project setup for Node/Python/Rust/Go, and baseline verification.
Executes implementation plans in current session by dispatching fresh subagents per independent task, with two-stage reviews: spec compliance then code quality.
Dispatches parallel agents to independently tackle 2+ tasks like separate test failures or subsystems without shared state or dependencies.
Bidirectional sync between forge sessions and Notion. Called by brainstorming, planning, and executing skills — never directly by the user.
Activation: Read .forge/config.json. If it doesn't exist or has no notion key, skip all Notion operations silently.
cat .forge/config.json 2>/dev/null
{
"notion": {
"plansPageId": "PAGE-ID",
"brainstormsPageId": "PAGE-ID"
}
}
Notion page IDs are stored in $SESSION_DIR/integration.json:
{
"notion": {
"planPageId": "notion-page-uuid",
"brainstormPageId": "notion-page-uuid"
}
}
| Tool | Purpose |
|---|---|
mcp__f4115dea-5c2c-4222-b470-58b9466e1181__notion-search | Find pages by name (for init + pull) |
mcp__f4115dea-5c2c-4222-b470-58b9466e1181__notion-fetch | Read a page's content (for pull) |
mcp__f4115dea-5c2c-4222-b470-58b9466e1181__notion-create-pages | Create a new page under a parent |
mcp__f4115dea-5c2c-4222-b470-58b9466e1181__notion-update-page | Update page title, properties, or content |
Called by brainstorming skill after writing $SESSION_DIR/brainstorm.md.
1. Read .forge/config.json → get brainstormsPageId
2. Check $SESSION_DIR/integration.json → does brainstormPageId already exist?
3a. If NO (first push):
- Call notion-create-pages(parentId=brainstormsPageId, title="Brainstorm s<id>: <brainstorm title>")
- Add full markdown content as page body
- Store returned pageId in $SESSION_DIR/integration.json under notion.brainstormPageId
3b. If YES (re-push / update):
- Call notion-update-page(pageId=brainstormPageId, content=<updated markdown>)
4. Print: "Brainstorm synced to Notion → <page title>"
Markdown → Notion content: Convert headings, bullets, and code blocks to Notion block format. Use the tool's native markdown support if available; otherwise map manually:
# heading → heading_1## heading → heading_2- item → bulleted_list_item```code``` → code blockCalled by planning skill after writing $SESSION_DIR/plan.md.
1. Read .forge/config.json → get plansPageId
2. Check $SESSION_DIR/integration.json → does planPageId already exist?
3a. If NO:
- Call notion-create-pages(parentId=plansPageId, title="Plan s<id>: <plan title>")
- Create page with:
- ## Summary section
- ## Tasks table (task ID | title | status | category | complexity)
- ## Execution Batches section
- ## Notes section
- Store returned pageId in $SESSION_DIR/integration.json under notion.planPageId
3b. If YES (re-push or status update):
- Call notion-update-page(pageId=planPageId, ...) to refresh Tasks table
4. Print: "Plan synced to Notion → <page title>"
Task status table format (as Notion table block):
| Task | Title | Status | Category | Complexity |
|------|-------|--------|----------|------------|
| T1 | ... | ⏳ pending | impl | low |
| T2 | ... | ✅ done | wiring | medium |
Status emojis: pending → ⏳, in-progress → 🔄, done → ✅, failed → ❌, blocked → 🚫, aborted → ⛔
Called by brainstorming/planning skill when user wants to use a Notion page as input.
1. Ask user for Notion page name or URL (AskQuestion)
2. Call notion-search(query=<name>) OR notion-fetch(url=<url>)
3. Extract text content from the page
4. Return content to calling skill as "additional context / input"
5. The calling skill uses this content in place of or alongside the user's direct input
Called by executing skill after each task completes.
1. Read $SESSION_DIR/integration.json → get planPageId
2. If no planPageId → skip
3. Read current task statuses from $SESSION_DIR/plan.md
4. Call notion-update-page(pageId=planPageId) with refreshed Tasks table
- Update status column for the completed/failed task
- Keep all other content intact
5. This is fire-and-forget — don't block execution on Notion update failures
Called by aborting skill.
1. Read $SESSION_DIR/integration.json → get planPageId
2. If no planPageId → skip
3. Call notion-update-page(pageId, add "⛔ Aborted at <timestamp>" to page top)
4. Refresh Tasks table with aborted statuses
.forge/config.json missing or has no notion key, return immediately