feed-the-machine 1.0.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.
Files changed (120) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +268 -0
  3. package/bin/generate-manifest.mjs +210 -0
  4. package/bin/install.mjs +114 -0
  5. package/ftm/SKILL.md +88 -0
  6. package/ftm-audit/SKILL.md +146 -0
  7. package/ftm-audit/references/protocols/PROJECT-PATTERNS.md +91 -0
  8. package/ftm-audit/references/protocols/RUNTIME-WIRING.md +66 -0
  9. package/ftm-audit/references/protocols/WIRING-CONTRACTS.md +135 -0
  10. package/ftm-audit/references/strategies/AUTO-FIX-STRATEGIES.md +69 -0
  11. package/ftm-audit/references/templates/REPORT-FORMAT.md +96 -0
  12. package/ftm-audit/scripts/run-knip.sh +23 -0
  13. package/ftm-audit.yml +2 -0
  14. package/ftm-brainstorm/SKILL.md +379 -0
  15. package/ftm-brainstorm/evals/evals.json +100 -0
  16. package/ftm-brainstorm/evals/promptfoo.yaml +109 -0
  17. package/ftm-brainstorm/references/agent-prompts.md +224 -0
  18. package/ftm-brainstorm/references/plan-template.md +121 -0
  19. package/ftm-brainstorm.yml +2 -0
  20. package/ftm-browse/SKILL.md +415 -0
  21. package/ftm-browse/daemon/browser-manager.ts +206 -0
  22. package/ftm-browse/daemon/bun.lock +30 -0
  23. package/ftm-browse/daemon/cli.ts +347 -0
  24. package/ftm-browse/daemon/commands.ts +410 -0
  25. package/ftm-browse/daemon/main.ts +357 -0
  26. package/ftm-browse/daemon/package.json +17 -0
  27. package/ftm-browse/daemon/server.ts +189 -0
  28. package/ftm-browse/daemon/snapshot.ts +519 -0
  29. package/ftm-browse/daemon/tsconfig.json +22 -0
  30. package/ftm-browse.yml +4 -0
  31. package/ftm-codex-gate/SKILL.md +302 -0
  32. package/ftm-codex-gate.yml +2 -0
  33. package/ftm-config/SKILL.md +310 -0
  34. package/ftm-config.default.yml +80 -0
  35. package/ftm-config.yml +2 -0
  36. package/ftm-council/SKILL.md +132 -0
  37. package/ftm-council/references/prompts/CLAUDE-INVESTIGATION.md +60 -0
  38. package/ftm-council/references/prompts/CODEX-INVESTIGATION.md +58 -0
  39. package/ftm-council/references/prompts/GEMINI-INVESTIGATION.md +58 -0
  40. package/ftm-council/references/prompts/REBUTTAL-TEMPLATE.md +57 -0
  41. package/ftm-council/references/protocols/PREREQUISITES.md +47 -0
  42. package/ftm-council/references/protocols/STEP-0-FRAMING.md +46 -0
  43. package/ftm-council.yml +2 -0
  44. package/ftm-dashboard.yml +4 -0
  45. package/ftm-debug/SKILL.md +146 -0
  46. package/ftm-debug/references/phases/PHASE-0-INTAKE.md +58 -0
  47. package/ftm-debug/references/phases/PHASE-1-TRIAGE.md +46 -0
  48. package/ftm-debug/references/phases/PHASE-2-WAR-ROOM-AGENTS.md +279 -0
  49. package/ftm-debug/references/phases/PHASE-3-TO-6-EXECUTION.md +436 -0
  50. package/ftm-debug/references/protocols/BLACKBOARD.md +86 -0
  51. package/ftm-debug/references/protocols/EDGE-CASES.md +103 -0
  52. package/ftm-debug.yml +2 -0
  53. package/ftm-diagram/SKILL.md +233 -0
  54. package/ftm-diagram.yml +2 -0
  55. package/ftm-executor/SKILL.md +657 -0
  56. package/ftm-executor/references/STYLE-TEMPLATE.md +73 -0
  57. package/ftm-executor/references/phases/PHASE-0-VERIFICATION.md +62 -0
  58. package/ftm-executor/references/phases/PHASE-2-AGENT-ASSEMBLY.md +34 -0
  59. package/ftm-executor/references/phases/PHASE-3-WORKTREES.md +38 -0
  60. package/ftm-executor/references/phases/PHASE-4-5-AUDIT.md +72 -0
  61. package/ftm-executor/references/phases/PHASE-4-DISPATCH.md +66 -0
  62. package/ftm-executor/references/phases/PHASE-5-5-CODEX-GATE.md +73 -0
  63. package/ftm-executor/references/protocols/DOCUMENTATION-BOOTSTRAP.md +36 -0
  64. package/ftm-executor/references/protocols/MODEL-PROFILE.md +44 -0
  65. package/ftm-executor/references/protocols/PROGRESS-TRACKING.md +66 -0
  66. package/ftm-executor/runtime/ftm-runtime.mjs +252 -0
  67. package/ftm-executor/runtime/package.json +8 -0
  68. package/ftm-executor.yml +2 -0
  69. package/ftm-git/SKILL.md +195 -0
  70. package/ftm-git/evals/evals.json +26 -0
  71. package/ftm-git/evals/promptfoo.yaml +75 -0
  72. package/ftm-git/hooks/post-commit-experience.sh +92 -0
  73. package/ftm-git/references/patterns/SECRET-PATTERNS.md +104 -0
  74. package/ftm-git/references/protocols/REMEDIATION.md +139 -0
  75. package/ftm-git/scripts/pre-commit-secrets.sh +110 -0
  76. package/ftm-git.yml +2 -0
  77. package/ftm-intent/SKILL.md +198 -0
  78. package/ftm-intent.yml +2 -0
  79. package/ftm-map.yml +2 -0
  80. package/ftm-mind/SKILL.md +986 -0
  81. package/ftm-mind/evals/promptfoo.yaml +142 -0
  82. package/ftm-mind/references/blackboard-schema.md +328 -0
  83. package/ftm-mind/references/complexity-guide.md +110 -0
  84. package/ftm-mind/references/event-registry.md +299 -0
  85. package/ftm-mind/references/mcp-inventory.md +296 -0
  86. package/ftm-mind/references/protocols/COMPLEXITY-SIZING.md +72 -0
  87. package/ftm-mind/references/protocols/MCP-HEURISTICS.md +32 -0
  88. package/ftm-mind/references/protocols/PLAN-APPROVAL.md +80 -0
  89. package/ftm-mind/references/reflexion-protocol.md +249 -0
  90. package/ftm-mind/references/routing/SCENARIOS.md +22 -0
  91. package/ftm-mind/references/routing-scenarios.md +35 -0
  92. package/ftm-mind.yml +2 -0
  93. package/ftm-pause/SKILL.md +133 -0
  94. package/ftm-pause/references/protocols/SKILL-RESTORE-PROTOCOLS.md +186 -0
  95. package/ftm-pause/references/protocols/VALIDATION.md +80 -0
  96. package/ftm-pause.yml +2 -0
  97. package/ftm-researcher.yml +2 -0
  98. package/ftm-resume/SKILL.md +166 -0
  99. package/ftm-resume/references/protocols/VALIDATION.md +172 -0
  100. package/ftm-resume.yml +2 -0
  101. package/ftm-retro/SKILL.md +189 -0
  102. package/ftm-retro/references/protocols/SCORING-RUBRICS.md +89 -0
  103. package/ftm-retro/references/templates/REPORT-FORMAT.md +109 -0
  104. package/ftm-retro.yml +2 -0
  105. package/ftm-routine.yml +4 -0
  106. package/ftm-state/blackboard/context.json +23 -0
  107. package/ftm-state/blackboard/experiences/index.json +9 -0
  108. package/ftm-state/blackboard/patterns.json +6 -0
  109. package/ftm-state/schemas/context.schema.json +130 -0
  110. package/ftm-state/schemas/experience-index.schema.json +77 -0
  111. package/ftm-state/schemas/experience.schema.json +78 -0
  112. package/ftm-state/schemas/patterns.schema.json +44 -0
  113. package/ftm-upgrade/SKILL.md +153 -0
  114. package/ftm-upgrade/scripts/check-version.sh +76 -0
  115. package/ftm-upgrade/scripts/upgrade.sh +143 -0
  116. package/ftm-upgrade.yml +2 -0
  117. package/ftm.yml +2 -0
  118. package/install.sh +102 -0
  119. package/package.json +74 -0
  120. package/uninstall.sh +25 -0
@@ -0,0 +1,104 @@
1
+ # Secret Patterns — Extended Pattern Library
2
+
3
+ Full regex pattern library for Phase 1 scanning. Tier 1 patterns are high-confidence; Tier 2 require surrounding context validation.
4
+
5
+ ---
6
+
7
+ ## Tier 1: High-Confidence Patterns (almost certainly real secrets)
8
+
9
+ These patterns have distinctive prefixes or structures that make false positives rare. Run in parallel.
10
+
11
+ ```
12
+ # AWS
13
+ AKIA[0-9A-Z]{16} # AWS Access Key ID
14
+ amzn\.mws\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} # AWS MWS
15
+
16
+ # GitHub
17
+ ghp_[A-Za-z0-9_]{36} # GitHub PAT (classic)
18
+ gho_[A-Za-z0-9_]{36} # GitHub OAuth
19
+ ghu_[A-Za-z0-9_]{36} # GitHub user token
20
+ ghs_[A-Za-z0-9_]{36} # GitHub server token
21
+ github_pat_[A-Za-z0-9_]{82} # GitHub fine-grained PAT
22
+
23
+ # Slack
24
+ xoxb-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24} # Slack bot token
25
+ xoxp-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24,34} # Slack user token
26
+ xoxa-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24,34} # Slack app token
27
+ xoxr-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24,34} # Slack refresh token
28
+
29
+ # Google
30
+ AIza[0-9A-Za-z\-_]{35} # Google API key
31
+
32
+ # Stripe
33
+ sk_live_[0-9a-zA-Z]{24,} # Stripe secret key (live)
34
+ sk_test_[0-9a-zA-Z]{24,} # Stripe secret key (test)
35
+ rk_live_[0-9a-zA-Z]{24,} # Stripe restricted key
36
+
37
+ # Other services
38
+ SG\.[A-Za-z0-9\-_]{22}\.[A-Za-z0-9\-_]{43} # SendGrid
39
+ SK[0-9a-fA-F]{32} # Twilio
40
+ npm_[A-Za-z0-9]{36} # npm token
41
+ pypi-[A-Za-z0-9\-_]{100,} # PyPI token
42
+ glpat-[A-Za-z0-9\-_]{20,} # GitLab PAT
43
+ -----BEGIN (RSA|DSA|EC|OPENSSH|PGP) PRIVATE KEY----- # Private keys
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Tier 2: Context-Dependent Patterns (need surrounding context to confirm)
49
+
50
+ These match common assignment patterns. Check that the value isn't a placeholder, empty string, or env var reference before flagging:
51
+
52
+ ```
53
+ # Generic key/secret assignments — flag if value looks real (not placeholder)
54
+ (api_key|apikey|api-key)\s*[:=]\s*["']?[A-Za-z0-9\-_]{16,}["']?
55
+ (secret|secret_key|client_secret)\s*[:=]\s*["']?[A-Za-z0-9\-_]{16,}["']?
56
+ (password|passwd|pwd)\s*[:=]\s*["']?[^\s"']{8,}["']?
57
+ (token|access_token|auth_token)\s*[:=]\s*["']?[A-Za-z0-9\-_.]{16,}["']?
58
+ (database_url|db_url|connection_string)\s*[:=]\s*["']?[^\s"']{20,}["']?
59
+
60
+ # Bearer tokens in code
61
+ bearer\s+[A-Za-z0-9\-._~+/]{20,}
62
+
63
+ # Webhook URLs with tokens
64
+ https://hooks\.slack\.com/services/T[A-Z0-9]{8,}/B[A-Z0-9]{8,}/[a-zA-Z0-9]{24}
65
+ ```
66
+
67
+ ---
68
+
69
+ ## What to Ignore (false positive suppression)
70
+
71
+ Skip matches that are clearly not real secrets:
72
+
73
+ - Values that are `""`, `''`, `None`, `null`, `undefined`, `TODO`, `CHANGEME`, `your-key-here`, `xxx`, `placeholder`, `example`, `test`, `dummy`, `fake`, `sample`
74
+ - References to environment variables: `os.environ[`, `process.env.`, `ENV[`, `${`, `os.getenv(`
75
+ - Lines that are comments (`#`, `//`, `/*`, `--`)
76
+ - Files in `node_modules/`, `.git/`, `vendor/`, `__pycache__/`, `dist/`, `build/`
77
+ - Files that are themselves `.env.example`, `.env.sample`, `.env.template`
78
+ - Lock files (`package-lock.json`, `yarn.lock`, `Gemfile.lock`, `poetry.lock`)
79
+ - Test fixtures where the "secret" is obviously fake (e.g., `test_api_key = "sk_test_abc123"` in a test file — but still flag `sk_live_*` in test files, those are real)
80
+
81
+ ---
82
+
83
+ ## Severity Classification
84
+
85
+ After validation, findings are sorted by severity:
86
+
87
+ | Severity | Meaning |
88
+ |---|---|
89
+ | **CRITICAL** | Tier 1 match (high-confidence secret) in a tracked or staged file |
90
+ | **HIGH** | Tier 2 confirmed match in a tracked or staged file |
91
+ | **MEDIUM** | `.env` file not in `.gitignore`, or secret in a fallback default |
92
+ | **LOW** | Secret in a gitignored file but the gitignore rule might be fragile |
93
+
94
+ ---
95
+
96
+ ## Per-Finding Record Format
97
+
98
+ For each finding, record:
99
+ - **file**: absolute path
100
+ - **line**: line number
101
+ - **pattern**: which pattern matched
102
+ - **tier**: 1 or 2
103
+ - **value_preview**: first 8 chars + `...` + last 4 chars (never log the full secret)
104
+ - **context**: the surrounding code (with the secret value masked)
@@ -0,0 +1,139 @@
1
+ # Remediation Protocol — Auto-Fix Steps
2
+
3
+ Detailed remediation steps for secrets found during Phase 1–2 scanning. Apply in sequence for each finding.
4
+
5
+ ---
6
+
7
+ ## Phase 3: Auto-Remediate
8
+
9
+ For each finding, apply the appropriate fix automatically. The goal is to make the code safe without breaking functionality.
10
+
11
+ ### Step 1: Ensure .env infrastructure exists
12
+
13
+ Check for a `.env` file in the project root. If it doesn't exist, create one with a header comment:
14
+
15
+ ```
16
+ # Environment variables — DO NOT COMMIT THIS FILE
17
+ # Copy .env.example for the template, fill in real values locally
18
+ ```
19
+
20
+ Check `.gitignore` for `.env` coverage. If missing, add:
21
+ ```
22
+ # Environment files with secrets
23
+ .env
24
+ .env.local
25
+ .env.production
26
+ .env.staging
27
+ .env.*.local
28
+ ```
29
+
30
+ ### Step 2: Extract secrets to .env
31
+
32
+ For each finding:
33
+
34
+ 1. **Choose an env var name** — derive it from the context. If the code says `STRIPE_API_KEY = "sk_live_..."`, the env var is `STRIPE_API_KEY`. If it says `api_key: "AIza..."`, infer from the file/service context (e.g., `GOOGLE_API_KEY`). Use SCREAMING_SNAKE_CASE.
35
+
36
+ 2. **Add to .env** — append `VAR_NAME=<actual-secret-value>` to `.env`. If the var already exists, don't duplicate it.
37
+
38
+ 3. **Add to .env.example** — create or update `.env.example` with `VAR_NAME=your-value-here` so other developers know the variable exists without seeing the real value.
39
+
40
+ ### Step 3: Refactor source files
41
+
42
+ Replace the hardcoded secret with an env var reference. Match the language/framework:
43
+
44
+ | Language | Pattern |
45
+ |---|---|
46
+ | Python | `os.environ["VAR_NAME"]` or `os.getenv("VAR_NAME")` (match existing style in file) |
47
+ | JavaScript/TypeScript | `process.env.VAR_NAME` |
48
+ | Ruby | `ENV["VAR_NAME"]` or `ENV.fetch("VAR_NAME")` |
49
+ | Go | `os.Getenv("VAR_NAME")` |
50
+ | Java | `System.getenv("VAR_NAME")` |
51
+ | Shell/Bash | `$VAR_NAME` or `${VAR_NAME}` |
52
+ | YAML/JSON config | `${VAR_NAME}` (if the framework supports interpolation) or add a comment pointing to the env var |
53
+
54
+ If the file doesn't already import the env-reading module (e.g., `import os` in Python, `require('dotenv').config()` in Node), add the import. Check if the project uses `python-dotenv`, `dotenv` (Node), or similar — if so, use the project's existing pattern for loading env vars.
55
+
56
+ ### Step 4: Unstage remediated files
57
+
58
+ After refactoring, make sure the `.env` file (with real secrets) is NOT staged:
59
+
60
+ ```bash
61
+ git reset HEAD .env 2>/dev/null # unstage if accidentally staged
62
+ ```
63
+
64
+ Stage the refactored source files (which now reference env vars instead of hardcoded secrets):
65
+
66
+ ```bash
67
+ git add <refactored-files>
68
+ ```
69
+
70
+ ### Step 5: Verify the fix
71
+
72
+ Re-run Phase 1 scan on the refactored files to confirm the secrets are gone. If any remain, loop back and fix. Do not proceed until the scan is clean.
73
+
74
+ ---
75
+
76
+ ## Phase 4: Report
77
+
78
+ After remediation (or if the scan was clean from the start), produce a summary:
79
+
80
+ **Clean scan:**
81
+ ```
82
+ ftm-git: Clean scan. 0 secrets found in <N> files scanned. Safe to commit.
83
+ ```
84
+
85
+ **After remediation:**
86
+ ```
87
+ ftm-git: Found <N> hardcoded secrets. Auto-remediated:
88
+
89
+ CRITICAL: sk_live_**** in src/payments.py:42 -> STRIPE_SECRET_KEY
90
+ HIGH: AIza**** in config/google.ts:18 -> GOOGLE_API_KEY
91
+ MEDIUM: .env was not in .gitignore -> added
92
+
93
+ Actions taken:
94
+ - Extracted <N> secrets to .env (gitignored)
95
+ - Created/updated .env.example with placeholder vars
96
+ - Refactored <N> source files to use env var references
97
+ - Updated .gitignore
98
+
99
+ Verify the app still works with the new env var setup, then commit.
100
+ ```
101
+
102
+ **Blocked (auto-fix not possible):**
103
+
104
+ Some secrets can't be auto-fixed — for example, a private key embedded in a binary file, or a secret in a format the skill can't safely refactor. In these cases:
105
+
106
+ ```
107
+ ftm-git: BLOCKED. Found secrets that require manual remediation:
108
+
109
+ CRITICAL: Private key in assets/cert.pem:1
110
+ -> Move this file outside the repo and reference via path env var
111
+
112
+ Action required: Fix the above manually, then run ftm-git again.
113
+ ```
114
+
115
+ ---
116
+
117
+ ## Phase 5: Git History Check (Manual Invocation Only)
118
+
119
+ When explicitly asked to do a deep scan (e.g., "scan the repo history for secrets"), also check past commits. This is expensive so it only runs on explicit request, not as part of the pre-commit gate.
120
+
121
+ ```bash
122
+ git log --all --diff-filter=A --name-only --pretty=format:"%H" -- "*.env" "*.pem" "*.key" "*credentials*" "*secret*"
123
+ ```
124
+
125
+ For each historically added sensitive file, check if it's still in the current tree. If it was added and later removed, warn that the secret is still in git history and suggest:
126
+
127
+ 1. Rotate the credential immediately (it's compromised)
128
+ 2. Use `git filter-repo` or BFG Repo Cleaner to purge from history if needed
129
+
130
+ ---
131
+
132
+ ## Operating Principles
133
+
134
+ 1. **Block first, fix second.** Never let a secret through while figuring out the fix. The commit waits.
135
+ 2. **Zero false negatives over zero false positives.** It's better to flag something that turns out to be harmless than to miss a real key.
136
+ 3. **Never log full secrets.** In all output, mask secret values. Show only enough to identify which secret it is (first 8 + last 4 chars).
137
+ 4. **Env vars are the escape hatch.** The remediation pattern is always: secret goes to gitignored .env, code references the env var.
138
+ 5. **Existing patterns win.** If the project already uses dotenv, Vault, AWS Secrets Manager, or any other secret management system, match that pattern rather than introducing a new one.
139
+ 6. **Test files are not exempt.** A real `sk_live_*` key in a test file is just as dangerous as one in production code. Only `sk_test_*` with obviously fake values get a pass.
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env bash
2
+ # ftm-git pre-commit hook — blocks commits containing hardcoded secrets
3
+ # Installed by the ftm-git skill on first invocation. Safe to remove with:
4
+ # rm .git/hooks/pre-commit (or edit to remove the ftm-git section)
5
+ #
6
+ # This hook scans staged files only (fast). The full ftm-git skill does
7
+ # deeper scanning with context validation and auto-remediation — this is
8
+ # the safety net that catches what slips through.
9
+
10
+ set -euo pipefail
11
+
12
+ RED='\033[0;31m'
13
+ YELLOW='\033[0;33m'
14
+ NC='\033[0m'
15
+
16
+ # Get list of staged files (excluding deletions)
17
+ STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR 2>/dev/null || true)
18
+ if [ -z "$STAGED_FILES" ]; then
19
+ exit 0
20
+ fi
21
+
22
+ # Skip binary files, lock files, and vendored directories
23
+ FILTERED_FILES=""
24
+ for f in $STAGED_FILES; do
25
+ case "$f" in
26
+ node_modules/*|vendor/*|.git/*|__pycache__/*|dist/*|build/*) continue ;;
27
+ package-lock.json|yarn.lock|Gemfile.lock|poetry.lock|pnpm-lock.yaml) continue ;;
28
+ *.png|*.jpg|*.gif|*.ico|*.woff|*.woff2|*.ttf|*.eot|*.pdf|*.zip|*.tar*) continue ;;
29
+ .env.example|.env.sample|.env.template) continue ;;
30
+ *) FILTERED_FILES="$FILTERED_FILES $f" ;;
31
+ esac
32
+ done
33
+
34
+ if [ -z "$FILTERED_FILES" ]; then
35
+ exit 0
36
+ fi
37
+
38
+ FOUND=0
39
+ FINDINGS=""
40
+
41
+ # Tier 1: High-confidence patterns — these almost never false-positive
42
+ # We scan staged content (not working tree) to catch exactly what would be committed
43
+ PATTERNS=(
44
+ 'AKIA[0-9A-Z]{16}' # AWS Access Key ID
45
+ 'ghp_[A-Za-z0-9_]{36}' # GitHub PAT
46
+ 'gho_[A-Za-z0-9_]{36}' # GitHub OAuth
47
+ 'ghu_[A-Za-z0-9_]{36}' # GitHub user token
48
+ 'ghs_[A-Za-z0-9_]{36}' # GitHub server token
49
+ 'github_pat_[A-Za-z0-9_]{82}' # GitHub fine-grained PAT
50
+ 'xoxb-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24}' # Slack bot token
51
+ 'xoxp-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24,34}' # Slack user token
52
+ 'xoxa-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24,34}' # Slack app token
53
+ 'AIza[0-9A-Za-z\-_]{35}' # Google API key
54
+ 'sk_live_[0-9a-zA-Z]{24,}' # Stripe live secret
55
+ 'sk_test_[0-9a-zA-Z]{24,}' # Stripe test secret
56
+ 'rk_live_[0-9a-zA-Z]{24,}' # Stripe restricted
57
+ 'SG\.[A-Za-z0-9\-_]{22}\.[A-Za-z0-9\-_]{43}' # SendGrid
58
+ 'SK[0-9a-fA-F]{32}' # Twilio
59
+ 'npm_[A-Za-z0-9]{36}' # npm token
60
+ 'glpat-[A-Za-z0-9\-_]{20,}' # GitLab PAT
61
+ '-----BEGIN (RSA|DSA|EC|OPENSSH|PGP) PRIVATE KEY-----' # Private keys
62
+ )
63
+
64
+ for f in $FILTERED_FILES; do
65
+ # Get the staged version of the file (what would actually be committed)
66
+ CONTENT=$(git show ":$f" 2>/dev/null || true)
67
+ if [ -z "$CONTENT" ]; then
68
+ continue
69
+ fi
70
+
71
+ for pattern in "${PATTERNS[@]}"; do
72
+ MATCHES=$(echo "$CONTENT" | grep -nE "$pattern" 2>/dev/null || true)
73
+ if [ -n "$MATCHES" ]; then
74
+ while IFS= read -r match; do
75
+ LINE_NUM=$(echo "$match" | cut -d: -f1)
76
+ # Mask the secret value in output (show first 8 chars only)
77
+ MASKED=$(echo "$match" | cut -d: -f2- | sed -E 's/([A-Za-z0-9_\-]{8})[A-Za-z0-9_\-]{8,}/\1****/g')
78
+ FINDINGS="${FINDINGS}\n ${RED}BLOCKED${NC} $f:$LINE_NUM $MASKED"
79
+ FOUND=$((FOUND + 1))
80
+ done <<< "$MATCHES"
81
+ fi
82
+ done
83
+ done
84
+
85
+ # Also check: is a .env file being committed?
86
+ for f in $STAGED_FILES; do
87
+ case "$f" in
88
+ .env|.env.local|.env.production|.env.staging|.env.*.local)
89
+ FINDINGS="${FINDINGS}\n ${YELLOW}WARNING${NC} $f is staged — this file typically contains secrets and should be gitignored"
90
+ FOUND=$((FOUND + 1))
91
+ ;;
92
+ esac
93
+ done
94
+
95
+ if [ "$FOUND" -gt 0 ]; then
96
+ echo ""
97
+ echo -e "${RED}ftm-git: COMMIT BLOCKED — $FOUND secret(s) detected in staged files${NC}"
98
+ echo ""
99
+ echo -e "$FINDINGS"
100
+ echo ""
101
+ echo "To fix: run /ftm-git for auto-remediation, or manually:"
102
+ echo " 1. Move secrets to .env (gitignored)"
103
+ echo " 2. Replace hardcoded values with env var references"
104
+ echo " 3. Stage the cleaned files and commit again"
105
+ echo ""
106
+ echo "To bypass (NOT recommended): git commit --no-verify"
107
+ exit 1
108
+ fi
109
+
110
+ exit 0
package/ftm-git.yml ADDED
@@ -0,0 +1,2 @@
1
+ name: ftm-git
2
+ description: Secret scanning and credential safety gate for git operations. Prevents API keys, tokens, passwords, and other secrets from ever being committed or pushed to remote repositories. Scans staged files, working tree, and git history for hardcoded credentials using regex pattern matching, then auto-remediates by extracting secrets to gitignored .env files and replacing hardcoded values with env var references. Use when user says "scan for secrets", "check for keys", "audit credentials", "ftm-git", "secret scan", "remove api keys", "check before push", or any time git commit/push operations are about to happen. Also auto-invoked by ftm-executor and ftm-mind before any commit or push operation. Even if the user just says "commit this" or "push to remote", this skill MUST run first. Do NOT use for general git workflow operations like branching or merging — that's git-workflow territory. This skill is specifically the security gate.
@@ -0,0 +1,198 @@
1
+ ---
2
+ name: ftm-intent
3
+ description: Manages the hierarchical INTENT.md documentation layer — root index with architecture decisions and module map, plus per-module INTENT.md files with function-level entries (does/why/relationships/decisions). Use when creating or updating intent documentation, bootstrapping a new project's intent layer, or when user says "update intent", "document intent", "ftm-intent", "what does this function do". Auto-invoked by ftm-executor after every commit to keep intent documentation in sync with code changes.
4
+ ---
5
+
6
+ ## Events
7
+
8
+ ### Emits
9
+ - `documentation_updated` — when one or more INTENT.md files are written or modified to reflect new or changed code
10
+ - `task_completed` — when the full intent sync pass completes (bootstrap or incremental)
11
+
12
+ ### Listens To
13
+ - `code_committed` — fast-path: automatically sync INTENT.md entries for every changed function after each commit
14
+
15
+ # Intent Documentation Manager
16
+
17
+ Manages the hierarchical INTENT.md documentation layer. This is the contract layer that Codex reads during code review and that enables conflict detection between Claude's intent and Codex's fixes. The "Why" field is what prevents Codex from reverting deliberate design choices.
18
+
19
+ ## Graph-Powered Mode (ftm-map integration)
20
+
21
+ Before running the standard analysis, check if the project has a code knowledge graph:
22
+
23
+ ```bash
24
+ if [ -f ".ftm-map/map.db" ]; then
25
+ # Use graph for faster, more consistent analysis
26
+ ftm-map/scripts/.venv/bin/python3 ftm-map/scripts/views.py generate-intent "$PROJECT_ROOT"
27
+ else
28
+ # Fall back to standard file-by-file analysis below
29
+ fi
30
+ ```
31
+
32
+ When `.ftm-map/map.db` exists:
33
+ 1. Delegate to `views.py generate-intent` which reads the graph and produces INTENT.md files
34
+ 2. The graph path is faster (single DB query vs. reading every file) and more consistent (same analysis for every commit)
35
+ 3. Supports `--files` flag for incremental: `views.py generate-intent --files changed1.ts,changed2.py`
36
+
37
+ When `.ftm-map/map.db` does NOT exist:
38
+ - Fall back to the existing Bootstrap/Incremental modes below
39
+ - The behavior is identical to the current skill — no breaking change
40
+
41
+ This integration means ftm-intent automatically gets better when ftm-map is available, without requiring migration.
42
+
43
+ ## Two Modes of Operation
44
+
45
+ ### Bootstrap Mode (no INTENT.md exists)
46
+ Scan the codebase from scratch and create the full hierarchy.
47
+
48
+ 1. Use Glob to discover all source files and identify module boundaries
49
+ 2. Use Read/Grep to understand key functions in each module
50
+ 3. Create root INTENT.md at the project root
51
+ 4. Create per-module INTENT.md files for each module directory
52
+ 5. Populate all entries based on what the code actually does
53
+
54
+ ### Incremental Mode (INTENT.md already exists)
55
+ Read the current state and update only what changed.
56
+
57
+ 1. Read root INTENT.md and all relevant module INTENT.md files
58
+ 2. Identify what's missing: new functions without entries, new modules without INTENT.md
59
+ 3. Identify what's stale: entries for deleted or renamed functions
60
+ 4. Update only the affected entries and module map rows — do not regenerate from scratch
61
+
62
+ ## Root INTENT.md Template
63
+
64
+ Create at the project root. This is the "subway map" — high level routing to module detail.
65
+
66
+ ```markdown
67
+ # [Project Name] — Intent
68
+
69
+ ## Vision
70
+ [2-3 sentence summary of what this project does and why it exists]
71
+
72
+ ## Architecture Decisions
73
+ | Decision | Choice | Reasoning |
74
+ |---|---|---|
75
+ | [decision point] | [what was chosen] | [why this was chosen over alternatives] |
76
+
77
+ ## Module Map
78
+ | Module | Purpose | Key Relationships |
79
+ |---|---|---|
80
+ | [path/to/module] | [what this module does in one sentence] | [depends on X / depended by Y] |
81
+
82
+ ## Cross-Cutting Decisions
83
+ - [pattern name]: [what it is and why it applies everywhere]
84
+ ```
85
+
86
+ **Rules for root INTENT.md:**
87
+ - Vision: Written once, updated only if the project's purpose changes
88
+ - Architecture Decisions: Add a row every time a non-obvious architectural choice is made
89
+ - Module Map: Add a row when a new module directory is created; remove when deleted; must stay in sync with actual filesystem
90
+ - Cross-Cutting Decisions: Patterns that apply across 3+ modules (error handling strategy, auth approach, data fetching pattern, etc.)
91
+
92
+ ## Per-Module INTENT.md Template
93
+
94
+ Create inside each module directory (e.g., `src/auth/INTENT.md`). This is the "street map" — ground level function detail.
95
+
96
+ ```markdown
97
+ # [Module Name] — Intent
98
+
99
+ ## Functions
100
+
101
+ ### functionName(param1: Type, param2: Type) → ReturnType
102
+ - **Does**: [one sentence — what it does, not how]
103
+ - **Why**: [why this function exists, what problem it solves, why this approach over alternatives]
104
+ - **Relationships**: [calls X, called by Y, reads from Z store, mutates W]
105
+ - **Decisions**: [deliberate choices that might look wrong to an outside reviewer — "uses polling instead of websockets because..."]
106
+
107
+ ### anotherFunction(param: Type) → ReturnType
108
+ - **Does**: ...
109
+ - **Why**: ...
110
+ - **Relationships**: ...
111
+ - **Decisions**: ...
112
+ ```
113
+
114
+ **Rules for per-module INTENT.md:**
115
+ - Every exported function MUST have an entry
116
+ - Every entry MUST have all four fields (Does / Why / Relationships / Decisions)
117
+ - If there are no deliberate decisions, write "None" in the Decisions field — do not omit the field
118
+ - Include the full function signature with types — this helps with quick lookup and makes entries grep-able
119
+ - Keep each field to one sentence. This is a contract, not prose documentation.
120
+
121
+ ## When to Update
122
+
123
+ | Event | Action |
124
+ |---|---|
125
+ | New function created | Add entry to module's INTENT.md |
126
+ | Function behavior changed | Update Does / Why / Decisions fields |
127
+ | Function deleted | Remove entry from module's INTENT.md |
128
+ | New module directory created | Create module INTENT.md + add row to root module map |
129
+ | Module deleted | Remove module INTENT.md + remove row from root module map |
130
+ | Architecture decision made | Add row to root INTENT.md decisions table |
131
+ | Cross-cutting pattern established | Add entry to root Cross-Cutting Decisions section |
132
+
133
+ ## The Why Field — Most Important
134
+
135
+ The "Why" field is what makes this system valuable. It is the explicit record of deliberate choices that might look like bugs or inefficiencies to a reviewer who wasn't there when the decision was made.
136
+
137
+ Good Why entries:
138
+ - "Exists because the provider SDK doesn't expose a batch endpoint — each call must be sequential"
139
+ - "Uses pessimistic locking instead of optimistic because this resource has high write contention in production"
140
+ - "Fetches on every render instead of caching because this data changes in real time and stale reads cause downstream errors"
141
+
142
+ Bad Why entries:
143
+ - "Needed for the feature to work"
144
+ - "Required by the system"
145
+ - "Called by the auth flow"
146
+
147
+ If you can't write a clear Why, it means the original reasoning wasn't captured. Try to infer it from surrounding code, comments, or git history. If it's truly unknown, write "Why unknown — inferred from usage: [your inference]".
148
+
149
+ ## Format Contract
150
+
151
+ Codex reads INTENT.md files during code review to detect conflicts between stated intent and proposed changes. For this to work, the format must be consistent.
152
+
153
+ **Required format — do not deviate:**
154
+ - Section header: `### functionName(params) → ReturnType`
155
+ - Four bullet fields in order: `- **Does**:`, `- **Why**:`, `- **Relationships**:`, `- **Decisions**:`
156
+ - No prose paragraphs inside function entries
157
+ - No nested bullets inside a field — one sentence per field, always
158
+
159
+ If a function is complex enough that one sentence isn't enough, the function is probably doing too much. Document what it does at the boundary level, not the implementation level.
160
+
161
+ ## Discovery Commands
162
+
163
+ Use these to find what needs to be documented:
164
+
165
+ - Find all module directories: `Glob("src/**/")` or `Glob("lib/**/")`
166
+ - Find existing INTENT.md files: `Glob("**/INTENT.md")`
167
+ - Find all exported functions in a module: `Grep("^export (function|const|async function)", path="src/module/")`
168
+ - Find functions called by a specific function: read the function body and trace calls
169
+ - Find what calls a specific function: `Grep("functionName", type="ts")` or equivalent
170
+
171
+ ## Bootstrap Execution Order
172
+
173
+ When creating the intent layer from scratch:
174
+
175
+ 1. Read the project root README or package.json to understand the project vision
176
+ 2. Run `Glob("src/**/")` (or equivalent for the project structure) to discover modules
177
+ 3. For each module, read key files to understand what functions exist and what they do
178
+ 4. Draft root INTENT.md — vision, then module map (one row per module), then architecture decisions from what you observed, then cross-cutting patterns
179
+ 5. For each module, draft module INTENT.md — one entry per exported function
180
+ 6. Write all files
181
+ 7. Report: list of files created, count of functions documented, any functions where Why was unclear
182
+
183
+ ## Incremental Execution Order
184
+
185
+ When updating after changes:
186
+
187
+ 1. Read root INTENT.md
188
+ 2. Read the INTENT.md for affected modules (or all modules if unsure what changed)
189
+ 3. Compare against current code — use Grep to find functions that don't have entries, entries that don't have corresponding functions
190
+ 4. Write updates — add missing entries, remove stale entries, update changed fields
191
+ 5. If new modules were added, create their INTENT.md and add rows to root module map
192
+ 6. Report: list of files updated, entries added, entries removed, entries modified
193
+
194
+ ---
195
+
196
+ ### Auto-Invocation by ftm-executor
197
+
198
+ This skill's format is used by ftm-executor's documentation pipeline. After every commit during plan execution, agents update INTENT.md (or DIAGRAM.mmd) entries following this skill's templates. The updates are automatic and don't require explicit skill invocation — agents reference the format directly.
package/ftm-intent.yml ADDED
@@ -0,0 +1,2 @@
1
+ name: ftm-intent
2
+ description: Manages the hierarchical INTENT.md documentation layer — root index with architecture decisions and module map, plus per-module INTENT.md files with function-level entries (does/why/relationships/decisions). Use when creating or updating intent documentation, bootstrapping a new project's intent layer, or when user says "update intent", "document intent", "ftm-intent", "what does this function do". Auto-invoked by ftm-executor after every commit to keep intent documentation in sync with code changes.
package/ftm-map.yml ADDED
@@ -0,0 +1,2 @@
1
+ name: ftm-map
2
+ description: Persistent code knowledge graph powered by tree-sitter and SQLite with FTS5 full-text search. Builds structural dependency graphs, enables blast radius analysis, dependency chain queries, and keyword-based code search. Use when the user asks "what breaks if I change X", "what depends on Y", "blast radius of Z", "where do we handle auth", "map this codebase", "index this project", "what calls function X", "show dependencies for Y". Also triggered by ftm-intent and ftm-diagram for graph-powered view generation. Triggers on "blast radius", "what breaks", "what calls", "what depends on", "where do we", "map codebase", "index", "code graph", "dependency chain", "ftm-map".