taip-connect 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "taip-connect",
3
+ "version": "0.5.0",
4
+ "description": "taip-connect — wire the hosted taip brain + context + taip-tools MCP servers into Claude Code (VS Code).",
5
+ "bin": {
6
+ "taip-connect": "bin/connect.js"
7
+ },
8
+ "type": "module",
9
+ "files": [
10
+ "bin/",
11
+ "packs/",
12
+ "README.md"
13
+ ],
14
+ "engines": {
15
+ "node": ">=20"
16
+ },
17
+ "license": "UNLICENSED",
18
+ "repository": "github:taip-ai/taip-agent"
19
+ }
@@ -0,0 +1,159 @@
1
+ ---
2
+ id: process/skills/taip-workflow-acceptance-testing
3
+ version: 1.0.1
4
+ trigger: "acceptance testing|run AT|acceptance test|sign off|ready for done|hotfix AT"
5
+ description: >
6
+ Runs acceptance testing against a plan's acceptance criteria or a PM tool's ticket list.
7
+ Walks each Given-When-Then AC, records Pass/Fail/Blocked, generates an AT report,
8
+ writes it to docs/tests/, updates the traceability matrix, and gates completion on sign-off.
9
+ If a PM tool binding (Plane/Jira) is active, also posts the report as a ticket comment
10
+ and gates the tool's "Done" transition. Works offline with no PM tool.
11
+ user-invocable: true
12
+ tags: [acceptance-testing, qa, verification, process]
13
+ attribution:
14
+ source: original
15
+ license: brain-official
16
+ author: brain Official
17
+ ---
18
+
19
+ # taip-workflow-acceptance-testing
20
+
21
+ Acceptance testing gate: load ACs → walk each → record results → write report → update traceability → gate sign-off.
22
+
23
+ ---
24
+
25
+ ## Step 1 — Determine scope
26
+
27
+ Ask in one message if not already provided:
28
+
29
+ 1. **Scope:** Plan file path (e.g. `docs/plans/2026-06-12-slug.md`) OR ticket key(s) if a PM tool is active
30
+ 2. **Hotfix?** Yes / No — if yes, all ACs must pass before going live
31
+
32
+ ---
33
+
34
+ ## Step 2 — Load acceptance criteria
35
+
36
+ **Path A — from plan file (default, no tool needed):**
37
+
38
+ 1. Read the plan file's `## Acceptance Tests` table
39
+ 2. If the table is empty or has no rows with `Given/When/Then`: stop and tell the user:
40
+ > "No acceptance criteria found in `## Acceptance Tests`. Please add Given/When/Then rows before running AT."
41
+ 3. Also load any linked `docs/tests/<slug>-acceptance.md` for full test case scenarios
42
+
43
+ **Path B — from PM tool (if active):**
44
+
45
+ 1. Fetch tickets in `Acceptance Testing` or `System Testing` state for the scope
46
+ 2. Parse each ticket's `## Acceptance Criteria` section for Given/When/Then lines
47
+ 3. If a ticket has no `## Acceptance Criteria`: skip it and warn the user
48
+
49
+ ---
50
+
51
+ ## Step 3 — Walk each AC and record result
52
+
53
+ For each AC, display:
54
+
55
+ ```
56
+ ───────────────────────────────────
57
+ AC{N}: Given {precondition}, when {action}, then {expected outcome}.
58
+ ───────────────────────────────────
59
+ Result? [Pass / Fail / Blocked] Notes (optional):
60
+ ```
61
+
62
+ WAIT for the user's result before moving to the next AC.
63
+
64
+ Build a results table:
65
+
66
+ | AC | Criterion (short) | Result | Notes |
67
+ |---|---|---|---|
68
+ | AC1 | Given … then … | ✅ Pass | — |
69
+ | AC2 | Given … then … | ❌ Fail | {notes} |
70
+
71
+ **Overall verdict:**
72
+ - **PASS** — all ACs pass
73
+ - **FAIL** — one or more ACs fail or are blocked
74
+
75
+ MUST NOT skip or estimate AC results — every AC must be explicitly recorded.
76
+
77
+ ---
78
+
79
+ ## Step 4 — Generate AT report
80
+
81
+ **Report filename:** `docs/tests/AT-<DDMMYYYY>-<scope-slug>.md`
82
+
83
+ Get today's date: `date +%d%m%Y`
84
+
85
+ **Report template:**
86
+
87
+ ```markdown
88
+ # Acceptance Test Report — {scope}
89
+
90
+ **Date:** {DD Month YYYY}
91
+ **Tester:** {user name}
92
+ **Type:** {Regular / Hotfix}
93
+ **Scope:** {plan file or ticket keys}
94
+
95
+ ## Summary
96
+
97
+ | Metric | Value |
98
+ |---|---|
99
+ | ACs tested | {N} |
100
+ | PASS | {N} |
101
+ | FAIL | {N} |
102
+ | Overall verdict | ✅ ALL PASS / ❌ FAILURES PRESENT |
103
+
104
+ {If hotfix:}
105
+ > ⚠ **Hotfix** — all ACs MUST pass. Live release: {BLOCKED / APPROVED}.
106
+
107
+ ## Results
108
+
109
+ | AC | Criterion | Result | Notes |
110
+ |---|---|---|---|
111
+ | AC1 | Given … then … | ✅ Pass | — |
112
+
113
+ ## Sign-off
114
+
115
+ - [ ] Sign-off: _____________________ Date: ___________
116
+ ```
117
+
118
+ Write the report to `docs/tests/AT-<DDMMYYYY>-<scope-slug>.md`.
119
+
120
+ ---
121
+
122
+ ## Step 5 — Update traceability matrix
123
+
124
+ Update `docs/traceability-matrix.md`:
125
+ - Add or update the row(s) linking the plan → this AT report
126
+ - Format: `[AT-DDMMYYYY-scope](tests/AT-DDMMYYYY-scope.md)`
127
+
128
+ If `docs/traceability-matrix.md` does not exist: create it from the traceability matrix template.
129
+
130
+ ---
131
+
132
+ ## Step 6 — PM tool sync (only if a tool binding is active)
133
+
134
+ **If Plane or Jira is configured:**
135
+
136
+ For each ticket in scope:
137
+ 1. Post the AT report as a comment on the ticket
138
+ 2. Comment MUST include: report link, overall verdict, AC table, next step
139
+
140
+ **If PASS:** ask "Has the tester/QM signed off on {ticket}? (Y/N)"
141
+ - Yes → transition ticket to **Done**
142
+ - No → print "Waiting for sign-off. Transition manually when approved."
143
+
144
+ **If FAIL:** do NOT transition. Print:
145
+ > "❌ {ticket} — FAIL. Return to developer. Ticket stays in Acceptance Testing."
146
+
147
+ **If no PM tool:** skip this step. Sign-off is recorded in the report file and traceability matrix.
148
+
149
+ ---
150
+
151
+ ## Hard fails
152
+
153
+ - MUST NOT mark a task complete without writing the AT report to `docs/tests/`
154
+ - MUST NOT mark a task complete without updating `docs/traceability-matrix.md`
155
+ - MUST NOT skip or estimate any AC — record every one as Pass / Fail / Blocked
156
+ - MUST NOT transition a PM ticket to Done if any AC is Fail or Blocked
157
+ - MUST NOT transition a PM ticket to Done without explicit sign-off confirmation from user
158
+ - MUST NOT transition a PM ticket to Done without posting a comment first (if tool active)
159
+ - For hotfix: MUST print live release BLOCKED message if any AC failed
@@ -0,0 +1,131 @@
1
+ ---
2
+ id: process/git/git-init
3
+ version: 1.1.0
4
+ trigger: "init git|setup git|initialize repo|git setup|setup branches|init branches"
5
+ description: >
6
+ Bootstraps a repo with the main/develop branch model. Checks pre-conditions,
7
+ creates develop from main if missing, pushes both branches to the remote,
8
+ emits a CLAUDE.md snippet, and optionally sets GitHub branch protection.
9
+ user-invocable: true
10
+ tags: [git, branching, workflow, init]
11
+ attribution:
12
+ source: original
13
+ license: brain-official
14
+ author: brain Official
15
+ ---
16
+
17
+ # taip-workflow-git-init
18
+
19
+ Set up the main/develop branch model in a repo. Run once on a new repo or to
20
+ align an existing repo to the strategy defined in `process/git/branch-strategy`.
21
+
22
+ ## Pre-conditions
23
+
24
+ **Check 1 — Git repo:**
25
+ ```bash
26
+ git rev-parse --git-dir
27
+ ```
28
+ If not a git repo: stop and tell the user to run `git init` first.
29
+
30
+ **Check 2 — At least one commit:**
31
+ ```bash
32
+ git log --oneline -1
33
+ ```
34
+ If empty repo: stop and tell the user to make an initial commit first.
35
+
36
+ **Check 3 — Remote configured (info only):**
37
+ ```bash
38
+ git remote -v
39
+ ```
40
+ If no remote: warn that branches will be created locally only. Continue.
41
+
42
+ **Check 4 — Current branch:**
43
+ Note the current branch name. If it is `master`, ask: "This repo uses `master`. Rename
44
+ to `main`? (Y / keep master)" — proceed based on answer. If it is already `main`, continue.
45
+
46
+ ## Step 1 — Ensure main exists
47
+
48
+ If current branch is `master` and user confirmed rename:
49
+ ```bash
50
+ git branch -m master main
51
+ git push origin main --force-with-lease # only if a remote is configured
52
+ git push origin --delete master # only if remote master exists
53
+ ```
54
+
55
+ If current branch is already `main` or another name: skip.
56
+
57
+ ## Step 2 — Create develop
58
+
59
+ Check if `develop` already exists:
60
+ ```bash
61
+ git branch --list develop
62
+ git branch -r --list origin/develop
63
+ ```
64
+
65
+ If `develop` does not exist locally:
66
+ ```bash
67
+ git checkout -b develop
68
+ git checkout - # return to previous branch
69
+ ```
70
+
71
+ If `develop` already exists locally: skip creation, report "develop already exists".
72
+
73
+ ## Step 3 — Push both branches to remote
74
+
75
+ Only if a remote is configured:
76
+ ```bash
77
+ git push -u origin main
78
+ git push -u origin develop
79
+ ```
80
+
81
+ If push fails due to no remote: skip silently (already warned in pre-conditions).
82
+
83
+ ## Step 4 — Emit CLAUDE.md snippet
84
+
85
+ Output this block to stdout so the user can paste it into their project's CLAUDE.md:
86
+
87
+ ```
88
+ ## Branch model
89
+
90
+ | Branch | Role |
91
+ |---|---|
92
+ | `main` | Production-stable — receives merges from `develop` at release time |
93
+ | `develop` | Integration branch — all feature and fix PRs target this |
94
+ | `feature/{slug}-{sequence_id}` | Task branches (from Plane issues) |
95
+ | `fix/{slug}` | Hotfix branches |
96
+
97
+ PRs: feature/* and fix/* → develop. develop → main at release only.
98
+ ```
99
+
100
+ ## Step 5 — Optional GitHub branch protection (if GitHub remote detected)
101
+
102
+ Check for GitHub remote:
103
+ ```bash
104
+ git remote get-url origin | grep github.com
105
+ ```
106
+
107
+ If GitHub remote found, ask: "Configure branch protection for main and develop via gh CLI? (Y / n)"
108
+
109
+ On Y:
110
+ ```bash
111
+ gh api repos/{owner}/{repo}/branches/main/protection \
112
+ --method PUT \
113
+ --input - <<'EOF'
114
+ {"required_status_checks":null,"enforce_admins":false,"required_pull_request_reviews":{"required_approving_review_count":0},"restrictions":null}
115
+ EOF
116
+
117
+ gh api repos/{owner}/{repo}/branches/develop/protection \
118
+ --method PUT \
119
+ --input - <<'EOF'
120
+ {"required_status_checks":null,"enforce_admins":false,"required_pull_request_reviews":{"required_approving_review_count":0},"restrictions":null}
121
+ EOF
122
+ ```
123
+
124
+ Report success or any error from the API.
125
+
126
+ ## Rules
127
+
128
+ - MUST NOT force-push `main` unless the user explicitly confirmed the `master` → `main` rename
129
+ - MUST NOT delete any remote branch without explicit user confirmation
130
+ - MUST report clearly what was created vs what already existed (idempotent output)
131
+ - If `develop` already exists: skip creation silently and confirm it's on the remote
@@ -0,0 +1,113 @@
1
+ ---
2
+ id: process/git/pr-creation
3
+ version: 1.1.0
4
+ trigger: "create pr|make pr|open pull request|submit pr|raise pr"
5
+ description: >
6
+ Creates a pull request with pre-flight checks. Verifies branch state, generates
7
+ a conventional PR title and description, references the plan file if one exists,
8
+ and outputs the PR link. Use when user says "create a PR", "open a pull request",
9
+ or "submit my changes".
10
+ user-invocable: true
11
+ tags: [git, pr, workflow]
12
+ attribution:
13
+ source: original
14
+ license: brain-official
15
+ author: brain Official
16
+ ---
17
+
18
+ # taip-workflow-git-pr
19
+
20
+ PR creation: pre-flight → draft PR → confirm → create.
21
+
22
+ ## Pre-conditions
23
+
24
+ **Check 1 — Not on main/master/develop:**
25
+ Verify current branch is NOT `main`, `master`, or `develop`. If it is: stop and ask the user to switch to a feature or fix branch.
26
+
27
+ **Check 2 — Uncommitted changes:**
28
+ If `git status` shows uncommitted changes: stop and ask the user to commit or stash first.
29
+
30
+ **Check 3 — CI status:**
31
+ Check if CI is passing on the current branch. Warn if CI status cannot be determined.
32
+
33
+ ## Step 1 — Gather info
34
+
35
+ Detect the base branch (default `develop`, fallback to `main` or `master` if `develop` does not exist):
36
+ ```bash
37
+ BASE=$(git branch -r | grep -E 'origin/(develop|main|master)' | sed 's|.*origin/||' | head -1)
38
+ BASE=${BASE:-main}
39
+ ```
40
+
41
+ Run:
42
+ ```bash
43
+ git log --oneline $(git merge-base HEAD $BASE)..HEAD
44
+ git diff $(git merge-base HEAD $BASE)..HEAD --stat
45
+ ```
46
+
47
+ Check for a plan file: `ls docs/plans/*.md` sorted by date — use the most recent one if it exists.
48
+
49
+ ## Step 2 — Draft PR
50
+
51
+ Generate:
52
+ - **Title**: conventional, ≤ 70 chars, derived from commits or task description
53
+ - **Body**: summary of what changed + why, plan reference if found, verification checklist
54
+
55
+ Template:
56
+ ```markdown
57
+ ## Summary
58
+ <2-4 bullet points of what changed>
59
+
60
+ ## Plan
61
+ <link to docs/plans/YYYY-MM-DD-slug.md if found>
62
+
63
+ ## Verification
64
+ - [ ] Tests pass
65
+ - [ ] Smoke check
66
+ - [ ] No secrets committed (git log --all --full-history -- "**/secrets/**")
67
+
68
+ 🤖 Generated with [brain taip-workflow-git-pr](https://taip.is)
69
+ ```
70
+
71
+ Show the draft and ask: "Create PR with this title and description? (Y / edit)"
72
+
73
+ ## Step 3 — Create PR (via the GitHub MCP tool)
74
+
75
+ On confirmation, open the PR through the **`github` MCP tool** — do **NOT** shell out to `gh`
76
+ (it is absent from the hosted/agent images and fails on SSH-only remotes).
77
+
78
+ **a. Derive the PR coordinates:**
79
+ ```bash
80
+ ORIGIN=$(git remote get-url origin)
81
+ # Strip the git@host: / https://host/ prefix and any trailing .git → owner/repo
82
+ SLUG=$(printf '%s' "$ORIGIN" | sed -E 's#^(git@[^:]+:|https?://[^/]+/)##; s#\.git$##')
83
+ OWNER=${SLUG%%/*}; REPO=${SLUG##*/}
84
+ OWNER=${OWNER:-taip-ai} # default org
85
+ HEAD=$(git rev-parse --abbrev-ref HEAD) # current feature branch
86
+ # BASE resolved in Step 1 (default develop)
87
+ ```
88
+
89
+ **b. Ensure HEAD is pushed** (GitHub needs the branch to exist on the remote):
90
+ ```bash
91
+ git push -u origin "$HEAD"
92
+ ```
93
+
94
+ **c. Call `create_pull_request`** — tool id `mcp__github__create_pull_request` in Claude Code
95
+ (`github__create_pull_request` behind the taip-tools proxy) with:
96
+ ```json
97
+ { "owner": "$OWNER", "repo": "$REPO", "base": "$BASE", "head": "$HEAD",
98
+ "title": "<title>", "body": "<body>" }
99
+ ```
100
+ Print the returned `html_url`.
101
+
102
+ **d. Fallback** — if the `github` tool is unavailable or `create_pull_request` errors, print the
103
+ compare link so the user can open the PR manually, plus the drafted title and body:
104
+ ```
105
+ https://github.com/$OWNER/$REPO/compare/$BASE...$HEAD?expand=1
106
+ ```
107
+
108
+ ## Rules
109
+
110
+ - MUST NOT create PR while on main/master
111
+ - MUST NOT create PR with uncommitted changes
112
+ - MUST NOT shell out to `gh` — open PRs via the `github` MCP tool (`create_pull_request`)
113
+ - PR description MUST include verification checklist
@@ -0,0 +1,188 @@
1
+ ---
2
+ id: process/skills/taip-workflow-plane-init
3
+ version: 2.0.1
4
+ trigger: "plane init|plane setup|init plane|setup plane|setup plane projects|create plane projects|deploy sprint runner|sprint runner setup"
5
+ description: >
6
+ Full bootstrap for the Plane + n8n sprint runner stack. Covers: deploy n8n and sprint
7
+ scripts to fridholmi, verify Plane API, create missing projects (with sprint label +
8
+ initial cycle), write SPRINT_PROJECTS into n8n config, restart n8n. Runs end-to-end
9
+ without manual steps. Requires: SSH access to fridholmi, plane_api_token in secrets.
10
+ user-invocable: true
11
+ tags: [plane, project-management, setup, sprint, n8n, init, deploy]
12
+ attribution:
13
+ source: original
14
+ license: brain-official
15
+ author: brain Official
16
+ ---
17
+
18
+ # taip-workflow-plane-init
19
+
20
+ Full Plane + sprint runner bootstrap. Zero manual steps.
21
+
22
+ Reference files (all in `fh-smarthome-docker`):
23
+ - `openclaw/sprint/projects.json` — repo ↔ Plane project mapping
24
+ - `openclaw/sprint/setup-plane-projects.sh` — project creation script
25
+ - `ansible/deploy-n8n-sprint.sh` — n8n + sprint deploy script
26
+ - `n8n/docker-compose.yml` — n8n service config
27
+
28
+ ---
29
+
30
+ ## Step 1 — Read current config
31
+
32
+ Read `openclaw/sprint/projects.json`. Confirm:
33
+ - `plane_api_url` is set
34
+ - At least one project entry exists with `workspace_slug`, `name`, `identifier`, `repo`
35
+
36
+ If `default_workspace_slug` is missing, ask for the primary Plane workspace slug.
37
+
38
+ ---
39
+
40
+ ## Step 2 — Check Plane API token
41
+
42
+ ```bash
43
+ ls -la openclaw/secrets/local/plane_api_token 2>/dev/null && wc -c openclaw/secrets/local/plane_api_token
44
+ ```
45
+
46
+ If missing or empty:
47
+ - Ask: "Paste your Plane API token (Profile → API Tokens in the Plane UI):"
48
+ - Write it: `echo "<token>" > openclaw/secrets/local/plane_api_token && chmod 0600 openclaw/secrets/local/plane_api_token`
49
+
50
+ ---
51
+
52
+ ## Step 3 — Check if n8n is deployed on the server
53
+
54
+ ```bash
55
+ ssh fridholmi "docker ps --filter name=fridholmit_n8n --format '{{.Names}}\t{{.Status}}' 2>/dev/null || echo 'not running'"
56
+ ```
57
+
58
+ **If n8n is already running:** skip to Step 5.
59
+
60
+ **If n8n is not running:** check if the deploy directory exists:
61
+ ```bash
62
+ ssh fridholmi "ls ~/fh-sprint/n8n/docker-compose.yml 2>/dev/null && echo 'deployed' || echo 'not deployed'"
63
+ ```
64
+
65
+ ---
66
+
67
+ ## Step 4 — Deploy n8n + sprint runner (if needed)
68
+
69
+ ```bash
70
+ bash openclaw/sprint/deploy-n8n-sprint.sh --host fridholmi --start
71
+ ```
72
+
73
+ Wait for confirmation that n8n started:
74
+ ```bash
75
+ ssh fridholmi "docker ps --filter name=fridholmit_n8n --format '{{.Names}}\t{{.Status}}'"
76
+ ```
77
+
78
+ If n8n fails to start, check logs:
79
+ ```bash
80
+ ssh fridholmi "docker logs fridholmit_n8n --tail=30"
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Step 5 — Verify Plane API connectivity
86
+
87
+ ```bash
88
+ TOKEN=$(cat openclaw/secrets/local/plane_api_token)
89
+ PLANE_URL=$(python3 -c "import json; d=json.load(open('openclaw/sprint/projects.json')); print(d['plane_api_url'])")
90
+ curl -sf "${PLANE_URL}/api/v1/users/me/" -H "X-Api-Key: ${TOKEN}" | python3 -c "import sys,json; d=json.load(sys.stdin); print('Authenticated as:', d.get('email'))"
91
+ ```
92
+
93
+ Note: Plane 1.3.x `/api/v1/workspaces/` returns 404 — use `/api/v1/users/me/` to verify.
94
+
95
+ If this fails:
96
+ - 401: wrong token → go back to Step 2
97
+ - Connection refused: Plane is down → `ssh fridholmi "docker ps --filter name=plane"`
98
+
99
+ ---
100
+
101
+ ## Step 6 — Create missing Plane projects (dry-run first)
102
+
103
+ Copy the setup script to fridholmi if not already there:
104
+ ```bash
105
+ rsync -av openclaw/sprint/setup-plane-projects.sh openclaw/sprint/projects.json \
106
+ fridholmi:~/fh-sprint/openclaw/sprint/
107
+ ```
108
+
109
+ Run dry-run on the server:
110
+ ```bash
111
+ ssh fridholmi "cd ~/fh-sprint && bash openclaw/sprint/setup-plane-projects.sh --dry-run"
112
+ ```
113
+
114
+ Show output to user. Ask: "Create these projects? (Y/N)"
115
+
116
+ WAIT for confirmation.
117
+
118
+ ---
119
+
120
+ ## Step 7 — Create projects + update n8n config
121
+
122
+ ```bash
123
+ ssh fridholmi "cd ~/fh-sprint && bash openclaw/sprint/setup-plane-projects.sh --update-compose"
124
+ ```
125
+
126
+ This:
127
+ 1. Creates missing Plane projects via REST API
128
+ 2. Creates the `ai-task` sprint label in each new project
129
+ 3. Creates "Sprint 1" cycle (today → +14 days)
130
+ 4. Writes `SPRINT_PROJECTS` into `~/fh-sprint/n8n/docker-compose.yml`
131
+
132
+ ---
133
+
134
+ ## Step 8 — Restart n8n to pick up SPRINT_PROJECTS
135
+
136
+ ```bash
137
+ ssh fridholmi "cd ~/fh-sprint && docker compose --project-directory . -f n8n/docker-compose.yml --env-file .env up -d"
138
+ ```
139
+
140
+ Verify:
141
+ ```bash
142
+ ssh fridholmi "docker ps --filter name=fridholmit_n8n --format '{{.Names}}\t{{.Status}}'"
143
+ ```
144
+
145
+ ---
146
+
147
+ ## Step 9 — Set TELEGRAM_CHAT_ID (if not set)
148
+
149
+ Check if it's configured:
150
+ ```bash
151
+ ssh fridholmi "grep TELEGRAM_CHAT_ID ~/fh-sprint/.env"
152
+ ```
153
+
154
+ If empty, ask: "What's your Telegram Chat ID? (from @userinfobot)" and update:
155
+ ```bash
156
+ ssh fridholmi "sed -i 's/TELEGRAM_CHAT_ID=/TELEGRAM_CHAT_ID=<id>/' ~/fh-sprint/.env"
157
+ ssh fridholmi "cd ~/fh-sprint && docker compose -f n8n/docker-compose.yml up -d"
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Step 10 — Summary
163
+
164
+ Print:
165
+ ```
166
+ ✅ Plane sprint runner is ready.
167
+
168
+ Projects configured:
169
+ <list from SPRINT_PROJECTS>
170
+
171
+ n8n UI: http://localhost:5678 (SSH tunnel: ssh -L 5678:127.0.0.1:5678 fridholmi -N)
172
+
173
+ Remaining manual step:
174
+ Add SSH credential 'Host SSH' in n8n UI → Settings → Credentials
175
+ (sshPrivateKey pointing to the server's SSH key)
176
+
177
+ To run a sprint: open n8n → 'Plane Sprint Runner' → Execute workflow
178
+ ```
179
+
180
+ ---
181
+
182
+ ## Hard fails
183
+
184
+ - MUST NOT create projects without running dry-run and getting user confirmation first
185
+ - MUST NOT write API tokens to any file other than `openclaw/secrets/local/plane_api_token`
186
+ - MUST NOT modify `n8n/docker-compose.yml` directly — the `--update-compose` flag on `setup-plane-projects.sh` handles this safely
187
+ - Plane 1.3.x quirks: hyphens in project names are rejected (script auto-converts to spaces); cycle creation requires `project_id` in body AND `cycle_view: true` on the project; `/api/v1/workspaces/` returns 404 (use `/api/v1/users/me/` for connectivity check)
188
+ - If n8n fails to start after 3 attempts: stop and show logs — do not retry silently