feed-the-machine 1.1.0 → 1.3.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/bin/generate-manifest.mjs +253 -0
- package/bin/install.mjs +372 -26
- package/docs/INBOX.md +233 -0
- package/ftm/SKILL.md +34 -0
- package/ftm-audit/SKILL.md +69 -0
- package/ftm-brainstorm/SKILL.md +51 -0
- package/ftm-browse/SKILL.md +39 -0
- package/ftm-capture/SKILL.md +370 -0
- package/ftm-capture.yml +4 -0
- package/ftm-codex-gate/SKILL.md +59 -0
- package/ftm-config/SKILL.md +35 -0
- package/ftm-council/SKILL.md +56 -0
- package/ftm-dashboard/SKILL.md +34 -0
- package/ftm-debug/SKILL.md +84 -0
- package/ftm-diagram/SKILL.md +44 -0
- package/ftm-executor/SKILL.md +97 -0
- package/ftm-git/SKILL.md +60 -0
- package/ftm-inbox/backend/__init__.py +0 -0
- package/ftm-inbox/backend/adapters/__init__.py +0 -0
- package/ftm-inbox/backend/adapters/_retry.py +64 -0
- package/ftm-inbox/backend/adapters/base.py +230 -0
- package/ftm-inbox/backend/adapters/freshservice.py +104 -0
- package/ftm-inbox/backend/adapters/gmail.py +125 -0
- package/ftm-inbox/backend/adapters/jira.py +136 -0
- package/ftm-inbox/backend/adapters/registry.py +192 -0
- package/ftm-inbox/backend/adapters/slack.py +110 -0
- package/ftm-inbox/backend/db/__init__.py +0 -0
- package/ftm-inbox/backend/db/connection.py +54 -0
- package/ftm-inbox/backend/db/schema.py +78 -0
- package/ftm-inbox/backend/executor/__init__.py +7 -0
- package/ftm-inbox/backend/executor/engine.py +149 -0
- package/ftm-inbox/backend/executor/step_runner.py +98 -0
- package/ftm-inbox/backend/main.py +103 -0
- package/ftm-inbox/backend/models/__init__.py +1 -0
- package/ftm-inbox/backend/models/unified_task.py +36 -0
- package/ftm-inbox/backend/planner/__init__.py +6 -0
- package/ftm-inbox/backend/planner/generator.py +127 -0
- package/ftm-inbox/backend/planner/schema.py +34 -0
- package/ftm-inbox/backend/requirements.txt +5 -0
- package/ftm-inbox/backend/routes/__init__.py +0 -0
- package/ftm-inbox/backend/routes/execute.py +186 -0
- package/ftm-inbox/backend/routes/health.py +52 -0
- package/ftm-inbox/backend/routes/inbox.py +68 -0
- package/ftm-inbox/backend/routes/plan.py +271 -0
- package/ftm-inbox/bin/launchagent.mjs +91 -0
- package/ftm-inbox/bin/setup.mjs +188 -0
- package/ftm-inbox/bin/start.sh +10 -0
- package/ftm-inbox/bin/status.sh +17 -0
- package/ftm-inbox/bin/stop.sh +8 -0
- package/ftm-inbox/config.example.yml +55 -0
- package/ftm-inbox/package-lock.json +2898 -0
- package/ftm-inbox/package.json +26 -0
- package/ftm-inbox/postcss.config.js +6 -0
- package/ftm-inbox/src/app.css +199 -0
- package/ftm-inbox/src/app.html +18 -0
- package/ftm-inbox/src/lib/api.ts +166 -0
- package/ftm-inbox/src/lib/components/ExecutionLog.svelte +81 -0
- package/ftm-inbox/src/lib/components/InboxFeed.svelte +143 -0
- package/ftm-inbox/src/lib/components/PlanStep.svelte +271 -0
- package/ftm-inbox/src/lib/components/PlanView.svelte +206 -0
- package/ftm-inbox/src/lib/components/StreamPanel.svelte +99 -0
- package/ftm-inbox/src/lib/components/TaskCard.svelte +190 -0
- package/ftm-inbox/src/lib/components/ui/EmptyState.svelte +63 -0
- package/ftm-inbox/src/lib/components/ui/KawaiiCard.svelte +86 -0
- package/ftm-inbox/src/lib/components/ui/PillButton.svelte +106 -0
- package/ftm-inbox/src/lib/components/ui/StatusBadge.svelte +67 -0
- package/ftm-inbox/src/lib/components/ui/StreamDrawer.svelte +149 -0
- package/ftm-inbox/src/lib/components/ui/ThemeToggle.svelte +80 -0
- package/ftm-inbox/src/lib/theme.ts +47 -0
- package/ftm-inbox/src/routes/+layout.svelte +76 -0
- package/ftm-inbox/src/routes/+page.svelte +401 -0
- package/ftm-inbox/static/favicon.png +0 -0
- package/ftm-inbox/svelte.config.js +12 -0
- package/ftm-inbox/tailwind.config.ts +63 -0
- package/ftm-inbox/tsconfig.json +13 -0
- package/ftm-inbox/vite.config.ts +6 -0
- package/ftm-intent/SKILL.md +44 -0
- package/ftm-manifest.json +3794 -0
- package/ftm-map/SKILL.md +50 -0
- package/ftm-mind/SKILL.md +173 -66
- package/ftm-pause/SKILL.md +43 -0
- package/ftm-researcher/SKILL.md +55 -0
- package/ftm-resume/SKILL.md +47 -0
- package/ftm-retro/SKILL.md +54 -0
- package/ftm-routine/SKILL.md +36 -0
- package/ftm-state/blackboard/capabilities.json +5 -0
- package/ftm-state/blackboard/capabilities.schema.json +27 -0
- package/ftm-upgrade/SKILL.md +41 -0
- package/hooks/ftm-blackboard-enforcer.sh +28 -27
- package/hooks/ftm-plan-gate.sh +21 -25
- package/install.sh +238 -111
- package/package.json +6 -2
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "FTM Capabilities Snapshot",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"required": ["discovered_at", "expires_at", "capabilities"],
|
|
6
|
+
"properties": {
|
|
7
|
+
"discovered_at": { "type": "string", "format": "date-time" },
|
|
8
|
+
"expires_at": { "type": "string", "format": "date-time" },
|
|
9
|
+
"capabilities": {
|
|
10
|
+
"type": "array",
|
|
11
|
+
"items": {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"required": ["name", "type", "verified", "confidence"],
|
|
14
|
+
"properties": {
|
|
15
|
+
"name": { "type": "string" },
|
|
16
|
+
"type": { "type": "string", "enum": ["mcp", "cli", "api", "env", "browser"] },
|
|
17
|
+
"verified": { "type": "boolean" },
|
|
18
|
+
"last_verified_at": { "type": "string", "format": "date-time" },
|
|
19
|
+
"operations_verified": { "type": "array", "items": { "type": "string" } },
|
|
20
|
+
"path": { "type": "string" },
|
|
21
|
+
"version": { "type": "string" },
|
|
22
|
+
"confidence": { "type": "string", "enum": ["verified", "known", "inferred", "unavailable"] }
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
package/ftm-upgrade/SKILL.md
CHANGED
|
@@ -151,3 +151,44 @@ Map `CHECK_FAILED <reason>` codes to user-facing messages:
|
|
|
151
151
|
**Cache location**: `~/.cache/ftm-brain/version-check`
|
|
152
152
|
**Version file**: `~/.claude/skills/ftm-version.txt`
|
|
153
153
|
**Repo**: `kkudumu/ftm-brain`
|
|
154
|
+
|
|
155
|
+
## Requirements
|
|
156
|
+
|
|
157
|
+
- tool: `gh` | required | GitHub CLI for querying releases from kkudumu/ftm-brain
|
|
158
|
+
- reference: `~/.claude/skills/ftm-upgrade/scripts/check-version.sh` | required | version check and cache script
|
|
159
|
+
- reference: `~/.claude/skills/ftm-upgrade/scripts/upgrade.sh` | required | download and install latest release script
|
|
160
|
+
- reference: `~/.claude/skills/ftm-version.txt` | optional | locally installed version number
|
|
161
|
+
|
|
162
|
+
## Risk
|
|
163
|
+
|
|
164
|
+
- level: high_write
|
|
165
|
+
- scope: downloads and overwrites skill files in ~/.claude/skills/ on upgrade; changes affect all ftm skill behavior going forward; irreversible without restoring previous version from backup or git
|
|
166
|
+
- rollback: restore from ~/.claude/skills/ backup if one was made before upgrade; or reinstall specific version by downloading an older release tarball
|
|
167
|
+
|
|
168
|
+
## Approval Gates
|
|
169
|
+
|
|
170
|
+
- trigger: UPGRADE_AVAILABLE detected | action: show current and latest version with changelog URL, wait for explicit "yes" confirmation before running upgrade.sh
|
|
171
|
+
- trigger: version check during preamble (passive notice pattern) | action: show one-line notice only, do NOT ask for confirmation or interrupt workflow
|
|
172
|
+
- complexity_routing: micro → auto | small → auto | medium → auto | large → auto | xl → auto
|
|
173
|
+
|
|
174
|
+
## Fallbacks
|
|
175
|
+
|
|
176
|
+
- condition: gh not installed | action: report "GitHub CLI not installed" with brew install gh instructions
|
|
177
|
+
- condition: no internet connection | action: report "Cannot reach GitHub. Check internet connection."
|
|
178
|
+
- condition: kkudumu/ftm-brain repo not found | action: report repo not found, suggest verifying access
|
|
179
|
+
- condition: no releases found | action: report "No releases found yet. Check back later."
|
|
180
|
+
- condition: upgrade.sh exits non-zero | action: report failure output, suggest running script manually
|
|
181
|
+
|
|
182
|
+
## Capabilities
|
|
183
|
+
|
|
184
|
+
- cli: `gh` | required | GitHub CLI for release queries and download
|
|
185
|
+
- cli: `bash` | required | for running check-version.sh and upgrade.sh
|
|
186
|
+
|
|
187
|
+
## Event Payloads
|
|
188
|
+
|
|
189
|
+
### task_completed
|
|
190
|
+
- skill: string — "ftm-upgrade"
|
|
191
|
+
- action: string — "check" | "upgrade" | "already_up_to_date"
|
|
192
|
+
- current_version: string | null — version before upgrade
|
|
193
|
+
- new_version: string | null — version after upgrade (null if no upgrade)
|
|
194
|
+
- status: string — "success" | "failed" | "up_to_date" | "check_failed"
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# ftm-blackboard-enforcer.sh
|
|
3
|
-
# Stop hook that
|
|
4
|
-
#
|
|
5
|
-
# to write the experience first.
|
|
3
|
+
# Stop hook that nudges Claude to record an experience if meaningful work
|
|
4
|
+
# was done but no blackboard entry was written.
|
|
6
5
|
#
|
|
7
|
-
#
|
|
6
|
+
# Uses additionalContext (not "decision: block") so Claude can still act on
|
|
7
|
+
# the reminder. A blocking stop creates a deadlock — Claude can't write files
|
|
8
|
+
# after the user ends the conversation.
|
|
9
|
+
#
|
|
10
|
+
# "Meaningful work" = 3+ edits tracked by the edit counter,
|
|
8
11
|
# or ftm skills were invoked (checked via context.json).
|
|
9
12
|
#
|
|
10
13
|
# Hook: Stop
|
|
@@ -13,29 +16,23 @@ set -euo pipefail
|
|
|
13
16
|
|
|
14
17
|
INPUT=$(cat)
|
|
15
18
|
|
|
16
|
-
# Prevent infinite loop — if this hook already fired, let Claude stop
|
|
17
|
-
STOP_HOOK_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false')
|
|
18
|
-
if [[ "$STOP_HOOK_ACTIVE" == "true" ]]; then
|
|
19
|
-
exit 0
|
|
20
|
-
fi
|
|
21
|
-
|
|
22
19
|
STATE_DIR="$HOME/.claude/ftm-state"
|
|
23
20
|
BB_DIR="$STATE_DIR/blackboard"
|
|
24
21
|
EDIT_COUNTER="$STATE_DIR/.edit-count"
|
|
25
22
|
CONTEXT_FILE="$BB_DIR/context.json"
|
|
26
23
|
EXPERIENCES_DIR="$BB_DIR/experiences"
|
|
27
|
-
EXPERIENCE_INDEX="$EXPERIENCES_DIR/index.json"
|
|
28
|
-
|
|
29
|
-
CURRENT_SESSION="${CLAUDE_SESSION_ID:-unknown}"
|
|
30
24
|
|
|
31
25
|
# Check 1: Were there meaningful edits this session?
|
|
26
|
+
# Edit counter contains just a number now (no session ID).
|
|
27
|
+
# If the counter file is recent (< 4 hours) and >= 3, count as meaningful.
|
|
32
28
|
HAD_EDITS=false
|
|
33
29
|
if [[ -f "$EDIT_COUNTER" ]]; then
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
COUNTER_AGE=$(( $(date +%s) - $(stat -c %Y "$EDIT_COUNTER" 2>/dev/null || stat -f %m "$EDIT_COUNTER" 2>/dev/null || echo "0") ))
|
|
31
|
+
if [[ "$COUNTER_AGE" -lt 14400 ]]; then
|
|
32
|
+
STORED_COUNT=$(cat "$EDIT_COUNTER" 2>/dev/null || echo "0")
|
|
33
|
+
if [[ "$STORED_COUNT" -ge 3 ]]; then
|
|
34
|
+
HAD_EDITS=true
|
|
35
|
+
fi
|
|
39
36
|
fi
|
|
40
37
|
fi
|
|
41
38
|
|
|
@@ -48,8 +45,10 @@ if [[ -f "$CONTEXT_FILE" ]]; then
|
|
|
48
45
|
fi
|
|
49
46
|
fi
|
|
50
47
|
|
|
51
|
-
# If no meaningful work detected, allow stop
|
|
48
|
+
# If no meaningful work detected, allow stop quietly
|
|
52
49
|
if [[ "$HAD_EDITS" == "false" && "$HAD_SKILLS" == "false" ]]; then
|
|
50
|
+
# Clean up session markers
|
|
51
|
+
rm -f "$EDIT_COUNTER" "$STATE_DIR/.plan-presented" 2>/dev/null
|
|
53
52
|
exit 0
|
|
54
53
|
fi
|
|
55
54
|
|
|
@@ -58,19 +57,17 @@ TODAY=$(date +%Y-%m-%d)
|
|
|
58
57
|
HAS_EXPERIENCE=false
|
|
59
58
|
|
|
60
59
|
if [[ -d "$EXPERIENCES_DIR" ]]; then
|
|
61
|
-
# Check for experience files created today
|
|
62
60
|
TODAY_EXPERIENCE=$(find "$EXPERIENCES_DIR" -name "${TODAY}*" -type f 2>/dev/null | head -1)
|
|
63
61
|
if [[ -n "$TODAY_EXPERIENCE" ]]; then
|
|
64
62
|
HAS_EXPERIENCE=true
|
|
65
63
|
fi
|
|
66
64
|
fi
|
|
67
65
|
|
|
68
|
-
# Also check if context.json was updated
|
|
66
|
+
# Also check if context.json was updated today (recent_decisions not empty)
|
|
69
67
|
if [[ -f "$CONTEXT_FILE" ]]; then
|
|
70
68
|
DECISIONS_COUNT=$(jq -r '.recent_decisions | length' "$CONTEXT_FILE" 2>/dev/null || echo "0")
|
|
71
69
|
LAST_UPDATED=$(jq -r '.session_metadata.last_updated // ""' "$CONTEXT_FILE" 2>/dev/null || echo "")
|
|
72
70
|
if [[ "$DECISIONS_COUNT" -gt 0 && -n "$LAST_UPDATED" ]]; then
|
|
73
|
-
# Check if last_updated is from today
|
|
74
71
|
if [[ "$LAST_UPDATED" == *"$TODAY"* ]]; then
|
|
75
72
|
HAS_EXPERIENCE=true
|
|
76
73
|
fi
|
|
@@ -78,17 +75,21 @@ if [[ -f "$CONTEXT_FILE" ]]; then
|
|
|
78
75
|
fi
|
|
79
76
|
|
|
80
77
|
if [[ "$HAS_EXPERIENCE" == "true" ]]; then
|
|
81
|
-
# Blackboard was written, allow stop
|
|
82
|
-
# Clean up session markers
|
|
78
|
+
# Blackboard was written, clean up and allow stop
|
|
83
79
|
rm -f "$EDIT_COUNTER" "$STATE_DIR/.plan-presented" 2>/dev/null
|
|
84
80
|
exit 0
|
|
85
81
|
fi
|
|
86
82
|
|
|
87
|
-
# Work was done but no blackboard write —
|
|
83
|
+
# Work was done but no blackboard write — nudge (don't block)
|
|
88
84
|
cat <<'JSON'
|
|
89
85
|
{
|
|
90
|
-
"
|
|
91
|
-
|
|
86
|
+
"hookSpecificOutput": {
|
|
87
|
+
"hookEventName": "Stop",
|
|
88
|
+
"additionalContext": "[ftm-blackboard-enforcer] You did meaningful work this session but did not record an experience to the blackboard. Before finishing, please: (1) Update ~/.claude/ftm-state/blackboard/context.json with current_task status and recent_decisions. (2) Write an experience file to ~/.claude/ftm-state/blackboard/experiences/ with task_type, tags, outcome, and lessons. (3) Update ~/.claude/ftm-state/blackboard/experiences/index.json with the new entry. This is how ftm learns — skipping it means the next session starts from zero."
|
|
89
|
+
}
|
|
92
90
|
}
|
|
93
91
|
JSON
|
|
92
|
+
|
|
93
|
+
# Clean up session markers regardless — don't let stale state carry over
|
|
94
|
+
rm -f "$EDIT_COUNTER" "$STATE_DIR/.plan-presented" 2>/dev/null
|
|
94
95
|
exit 0
|
package/hooks/ftm-plan-gate.sh
CHANGED
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
# ftm-plan-gate.sh
|
|
3
3
|
# PreToolUse hook for Edit/Write tools.
|
|
4
4
|
#
|
|
5
|
-
# Checks if a plan has been presented
|
|
6
|
-
#
|
|
7
|
-
# a medium+ task (detected by ftm-state), injects additionalContext
|
|
5
|
+
# Checks if a plan has been presented this session before allowing code edits.
|
|
6
|
+
# If no plan marker exists and the edit count is climbing, injects warnings
|
|
8
7
|
# telling Claude to stop and present a plan first.
|
|
9
8
|
#
|
|
10
|
-
# The marker file is created by Claude
|
|
11
|
-
#
|
|
12
|
-
#
|
|
9
|
+
# The marker file (~/.claude/ftm-state/.plan-presented) is created by Claude
|
|
10
|
+
# when it presents a plan. Any non-empty content counts as "plan presented".
|
|
11
|
+
# The file is cleaned up by the blackboard enforcer at session end.
|
|
13
12
|
#
|
|
14
13
|
# Hook: PreToolUse (matcher: Edit|Write)
|
|
15
14
|
|
|
@@ -25,9 +24,7 @@ fi
|
|
|
25
24
|
|
|
26
25
|
STATE_DIR="$HOME/.claude/ftm-state"
|
|
27
26
|
PLAN_MARKER="$STATE_DIR/.plan-presented"
|
|
28
|
-
SESSION_MARKER="$STATE_DIR/.session-id"
|
|
29
27
|
EDIT_COUNTER="$STATE_DIR/.edit-count"
|
|
30
|
-
SKILL_FILES_DIR="$HOME/.claude/skills"
|
|
31
28
|
|
|
32
29
|
# Get the file being edited
|
|
33
30
|
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""')
|
|
@@ -47,37 +44,36 @@ if [[ "$FILE_PATH" == *".claude/skills/"* ]] || \
|
|
|
47
44
|
exit 0
|
|
48
45
|
fi
|
|
49
46
|
|
|
50
|
-
# If plan marker exists
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
47
|
+
# If plan marker exists (any content), allow edits
|
|
48
|
+
if [[ -f "$PLAN_MARKER" ]] && [[ -s "$PLAN_MARKER" ]]; then
|
|
49
|
+
exit 0
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Reset edit counter if it's stale (older than 4 hours = likely a new session)
|
|
53
|
+
if [[ -f "$EDIT_COUNTER" ]]; then
|
|
54
|
+
COUNTER_AGE=$(( $(date +%s) - $(stat -c %Y "$EDIT_COUNTER" 2>/dev/null || echo "0") ))
|
|
55
|
+
if [[ "$COUNTER_AGE" -gt 14400 ]]; then
|
|
56
|
+
rm -f "$EDIT_COUNTER"
|
|
56
57
|
fi
|
|
57
58
|
fi
|
|
58
59
|
|
|
59
|
-
# Count edits
|
|
60
|
+
# Count edits without a plan marker
|
|
60
61
|
EDIT_COUNT=0
|
|
61
62
|
if [[ -f "$EDIT_COUNTER" ]]; then
|
|
62
|
-
|
|
63
|
-
STORED_SESSION=$(echo "$STORED" | cut -d: -f2)
|
|
64
|
-
if [[ "$STORED_SESSION" == "$CURRENT_SESSION" ]]; then
|
|
65
|
-
EDIT_COUNT=$(echo "$STORED" | cut -d: -f1)
|
|
66
|
-
fi
|
|
63
|
+
EDIT_COUNT=$(cat "$EDIT_COUNTER" 2>/dev/null || echo "0")
|
|
67
64
|
fi
|
|
68
65
|
|
|
69
66
|
EDIT_COUNT=$((EDIT_COUNT + 1))
|
|
70
|
-
echo "$
|
|
67
|
+
echo "$EDIT_COUNT" > "$EDIT_COUNTER"
|
|
71
68
|
|
|
72
|
-
# First 2 edits get a
|
|
69
|
+
# First 2 edits get a soft reminder (don't block — could be micro tasks)
|
|
73
70
|
# After 3+ edits without a plan marker, escalate the warning
|
|
74
71
|
if [[ $EDIT_COUNT -le 2 ]]; then
|
|
75
|
-
# Soft reminder — inject context but allow
|
|
76
72
|
cat <<'JSON'
|
|
77
73
|
{
|
|
78
74
|
"hookSpecificOutput": {
|
|
79
75
|
"hookEventName": "PreToolUse",
|
|
80
|
-
"additionalContext": "[ftm-plan-gate] You are editing files without having presented a plan this session. If this task is medium+ (touches 3+ files, involves external systems, or has stakeholder coordination), you MUST present a numbered plan and get user approval BEFORE editing code. If this is a micro/small task, you can proceed — but create the plan marker
|
|
76
|
+
"additionalContext": "[ftm-plan-gate] You are editing files without having presented a plan this session. If this task is medium+ (touches 3+ files, involves external systems, or has stakeholder coordination), you MUST present a numbered plan and get user approval BEFORE editing code. If this is a micro/small task, you can proceed — but create the plan marker: write any content to ~/.claude/ftm-state/.plan-presented to acknowledge you've considered it."
|
|
81
77
|
}
|
|
82
78
|
}
|
|
83
79
|
JSON
|
|
@@ -89,7 +85,7 @@ cat <<'JSON'
|
|
|
89
85
|
{
|
|
90
86
|
"hookSpecificOutput": {
|
|
91
87
|
"hookEventName": "PreToolUse",
|
|
92
|
-
"additionalContext": "[ftm-plan-gate WARNING] You have made 3+ file edits this session without presenting a plan. This is exactly the 'grinding without a plan' pattern that ftm-mind is supposed to prevent. STOP editing and do one of: (1) Present a numbered plan to the user and wait for approval, then write
|
|
88
|
+
"additionalContext": "[ftm-plan-gate WARNING] You have made 3+ file edits this session without presenting a plan. This is exactly the 'grinding without a plan' pattern that ftm-mind is supposed to prevent. STOP editing and do one of: (1) Present a numbered plan to the user and wait for approval, then write any content to ~/.claude/ftm-state/.plan-presented. (2) If the user explicitly said 'just do it' or this is genuinely a micro task, write the plan marker to acknowledge you've considered it. Do NOT continue editing without addressing this."
|
|
93
89
|
}
|
|
94
90
|
}
|
|
95
91
|
JSON
|