toga-ai 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 (62) hide show
  1. package/.claude/settings.json +119 -0
  2. package/.claude-plugin/marketplace.json +87 -0
  3. package/.claude-plugin/plugin.json +22 -0
  4. package/CLAUDE.md +161 -0
  5. package/README.md +72 -0
  6. package/agents/framework-pattern-checker.md +67 -0
  7. package/agents/harness-optimizer.md +102 -0
  8. package/agents/knowledge-writer.md +62 -0
  9. package/agents/php-build-resolver.md +51 -0
  10. package/agents/php-reviewer.md +51 -0
  11. package/agents/planner.md +88 -0
  12. package/agents/session-capture.md +101 -0
  13. package/agents/sql-reviewer.md +67 -0
  14. package/contexts/dev.md +43 -0
  15. package/contexts/research.md +49 -0
  16. package/contexts/review.md +37 -0
  17. package/knowledge/1.0/apps/library/INDEX.md +5 -0
  18. package/knowledge/1.0/apps/library/architecture.md +105 -0
  19. package/knowledge/1.0/apps/worker/INDEX.md +5 -0
  20. package/knowledge/1.0/apps/worker/architecture.md +223 -0
  21. package/knowledge/1.0/standards/backend-php.md +450 -0
  22. package/knowledge/2.0/apps/_underscore/INDEX.md +6 -0
  23. package/knowledge/2.0/apps/_underscore/architecture.md +183 -0
  24. package/knowledge/2.0/apps/_underscore/features/recursive-item-fulfillments.md +111 -0
  25. package/knowledge/2.0/apps/api2/INDEX.md +5 -0
  26. package/knowledge/2.0/apps/api2/architecture.md +162 -0
  27. package/knowledge/2.0/apps/worker2/INDEX.md +6 -0
  28. package/knowledge/2.0/apps/worker2/architecture.md +127 -0
  29. package/knowledge/2.0/apps/worker2/features/creating-worker-actions.md +135 -0
  30. package/knowledge/2.0/standards/backend-php.md +710 -0
  31. package/knowledge/CONVENTIONS.md +117 -0
  32. package/knowledge/INDEX.md +19 -0
  33. package/knowledge/clients/.gitkeep +0 -0
  34. package/knowledge/registry.json +7 -0
  35. package/knowledge.js +384 -0
  36. package/mcp-configs/README.md +72 -0
  37. package/mcp-configs/mcp-servers.json +23 -0
  38. package/package.json +50 -0
  39. package/rules/README.md +53 -0
  40. package/rules/common/coding-style.md +123 -0
  41. package/rules/common/git-workflow.md +72 -0
  42. package/rules/common/security.md +118 -0
  43. package/rules/common/testing.md +74 -0
  44. package/rules/php/app-framework.md +104 -0
  45. package/rules/php/underscore-framework.md +111 -0
  46. package/scripts/harness.js +605 -0
  47. package/scripts/hooks/evaluate-session.js +55 -0
  48. package/scripts/hooks/post-edit-validate.js +102 -0
  49. package/scripts/hooks/session-end.js +13 -0
  50. package/scripts/hooks/session-start.js +57 -0
  51. package/scripts/install.js +611 -0
  52. package/scripts/pre-commit +46 -0
  53. package/skills/capture/SKILL.md +294 -0
  54. package/skills/code-review/SKILL.md +140 -0
  55. package/skills/create-elastic-beanstalk/SKILL.md +217 -0
  56. package/skills/harness-audit/SKILL.md +152 -0
  57. package/skills/kickoff/SKILL.md +151 -0
  58. package/skills/php-patterns/SKILL.md +296 -0
  59. package/skills/session-resume/SKILL.md +156 -0
  60. package/skills/session-save/SKILL.md +158 -0
  61. package/skills/sync-team-skills/SKILL.md +87 -0
  62. package/sync-skills.js +71 -0
@@ -0,0 +1,294 @@
1
+ ---
2
+ name: capture
3
+ description: End-of-session knowledge writer for TOGA Technology projects. Run this at the END of a coding session to record what you worked on into the team `claude` knowledge base. It figures out what changed this session, matches it against existing knowledge, and proposes create/update/retire changes for one-tap approval — then writes them, keeping registry.json, frontmatter, and INDEX files consistent. Trigger whenever the user says "capture", "wrap up", "save my work to the knowledge base", "I'm done — record this", or finishes a feature and wants it documented.
4
+ ---
5
+
6
+ # Capture — record this session's work into the team knowledge base
7
+
8
+ You are the **only** editor of the knowledge base; developers never hand-edit it. So you
9
+ must keep everything consistent and **ask whenever a required fact is missing — never
10
+ assume**. Nothing is written until the developer approves your proposal.
11
+
12
+ ### Contribution model
13
+
14
+ Every `/capture` automatically pushes new knowledge back to the team git repo after
15
+ validate + index succeed:
16
+
17
+ - Teammates get it on their **next `npx toga-harness`** run, which pulls the git repo
18
+ before installing — so the two-way loop is:
19
+ 1. `npx toga-harness` seeds knowledge from the npm bundle
20
+ 2. `/capture` grows the knowledge base and pushes it back to git
21
+ 3. Teammates run `npx toga-harness` → git pull delivers the new docs → they get it
22
+ - The push is **non-blocking**: if offline or credentials are missing, capture is still
23
+ successful and you report a reminder to push manually.
24
+ - Only `knowledge/` files are ever staged — source code is never touched.
25
+
26
+ ## Core data model (same as `knowledge/CONVENTIONS.md` and the `kickoff` skill)
27
+
28
+ - Knowledge lives in the **`claude` repo** under `knowledge/`, partitioned by framework
29
+ (`1.0/` = `App_`/`library`, `2.0/` = `_underscore`).
30
+ - `apps/<repo>/architecture.md` + `features/*.md`; `standards/*.md`; top-level
31
+ `clients/<client>/{profile.md, features/, workflows/}`. App folders keyed by **repo name**.
32
+ - `registry.json` maps **repo ↔ project ↔ framework ↔ role(core|app) ↔ dependsOn**.
33
+ - Doc types: `feature`, `client-feature`, `workflow`, `architecture` (elevated),
34
+ `standard` (elevated).
35
+
36
+ ## Step 1 — Resolve the team-repo (`claude`) path
37
+
38
+ Same as kickoff: Claude memory `team-repo-path` → env `CLAUDE_TEAM_REPO` → auto-discover
39
+ (`./claude`, `../claude`, `../../claude`, walk up for `knowledge/INDEX.md`) → ask. Persist a
40
+ `team-repo-path` memory if missing. Call the helper as `node "<TEAM_REPO>/knowledge.js" …`.
41
+
42
+ ## Step 2 — Determine framework / repo / project (ask if unknown)
43
+
44
+ 1. From the **live session context**, identify what was built, changed, debugged, or decided,
45
+ and which source files were touched.
46
+ 2. Identify the **repo** from the working path: match against your remembered `repo-path-<repo>`
47
+ memories; otherwise use the repo folder under a `C:\WWW\1.0` (→ framework 1.0) or
48
+ `C:\WWW\2.0` (→ framework 2.0) tree **as a suggestion to confirm, not a fact to assume**.
49
+ 3. Look the repo up in `registry.json` to get its `framework` and `project`.
50
+ - If the repo is **not registered**, run **New-repo onboarding** (below) — ask everything.
51
+ - If you cannot confidently determine the repo/framework/project/client, **ask**.
52
+
53
+ ## Step 3 — Match against existing knowledge
54
+
55
+ For each distinct thing worked on, search for a doc that already covers it:
56
+
57
+ ```
58
+ node "<TEAM_REPO>/knowledge.js" search --framework=<fw> --repo=<repo> --file=<touched-path>
59
+ node "<TEAM_REPO>/knowledge.js" search --framework=<fw> --repo=<repo> --q=<keywords>
60
+ ```
61
+
62
+ Classify each item as **CREATE** (no doc yet), **UPDATE** (a doc exists and needs new
63
+ content / a new `files:` entry / a gotcha), or **DEPRECATE/DELETE** (the doc describes
64
+ something now removed or obsolete).
65
+
66
+ ## Step 4 — Build the proposal (one-tap approval)
67
+
68
+ Show a short, scannable, framework+repo-qualified plan, then the proposed content/diffs.
69
+ Mark any `architecture` or `standard` change as **⚠ ELEVATED** (senior-owned). Example:
70
+
71
+ ```
72
+ CREATE 2.0/apps/worker2/features/clickup-deploy.md (feature)
73
+ UPDATE 2.0/apps/worker2/features/creating-worker-actions.md (add files: + gotcha)
74
+ ⚠ ELEVATED 2.0/standards/backend-php.md (new cron-locking rule)
75
+ DELETE 2.0/apps/worker2/features/old-thing.md (removed this session)
76
+ ```
77
+
78
+ Ask the developer to approve. They may accept all, accept some, or edit. **Write nothing
79
+ until they confirm.** If a needed placement detail is ambiguous (which client? new vs.
80
+ update?), ask before proposing.
81
+
82
+ ## Step 5 — Apply the approved changes
83
+
84
+ Write/update/remove docs using the templates below. For every doc set/refresh frontmatter:
85
+ `framework`, `repo` (omit for pure client docs), `project`, `client` (`shared` for app docs;
86
+ a real slug for client docs), `type`, `status`, `updated` (today's date), `owners`, `files`,
87
+ `related`. Add `related:` cross-links (a `client-feature` must link back to the shared
88
+ `apps/<repo>/features/<base>.md`). If a new repo was onboarded, append it to `registry.json`.
89
+
90
+ ## Step 6 — Re-index and guard integrity (mandatory)
91
+
92
+ ```
93
+ node "<TEAM_REPO>/knowledge.js" index
94
+ node "<TEAM_REPO>/knowledge.js" validate
95
+ ```
96
+
97
+ `index` rebuilds all `INDEX.md` files from frontmatter (never hand-edit them). If `validate`
98
+ reports any error, **stop and fix it** before telling the developer you're done — do not
99
+ report success on an inconsistent knowledge base.
100
+
101
+ ## Step 7 — Auto-push to share with teammates
102
+
103
+ After validate + index succeed, stage and push only `knowledge/` changes to a
104
+ **personal branch** so a maintainer can review before merging to main.
105
+
106
+ ```bash
107
+ # Derive branch name from git user — e.g. knowledge/john-smith
108
+ BRANCH="knowledge/$(git -C "<TEAM_REPO>" config user.name | tr ' ' '-' | tr '[:upper:]' '[:lower:]')"
109
+
110
+ # Stage only knowledge/ — never stages source code
111
+ git -C "<TEAM_REPO>" add knowledge/
112
+ git -C "<TEAM_REPO>" diff --cached --quiet || git -C "<TEAM_REPO>" commit -m "knowledge: <brief description of what was captured>"
113
+
114
+ # Push to personal branch — does not touch main
115
+ git -C "<TEAM_REPO>" push origin HEAD:"$BRANCH"
116
+ ```
117
+
118
+ Replace `<brief description of what was captured>` with a one-line summary of the docs
119
+ written this capture (e.g. `"knowledge: add clickup-deploy feature doc for worker2"`).
120
+
121
+ **If push succeeds:** report
122
+ > "✓ Knowledge pushed to branch `knowledge/<your-name>` — a maintainer will review and merge to main"
123
+
124
+ **If push fails** (offline, no credentials, diverged branch, or any other error): do
125
+ **NOT** error out. Report:
126
+ > "⚠ Could not push — run `git -C <TEAM_REPO> push origin HEAD:knowledge/<your-name>` when ready"
127
+ and still consider the capture session successful.
128
+
129
+ Never stage anything outside `knowledge/`. If `git diff --cached` would include files
130
+ outside `knowledge/`, abort the commit and warn: "Unexpected staged files outside
131
+ `knowledge/` — push skipped. Review and push manually."
132
+
133
+ **Devs do not need write access to main.** They only need permission to push to
134
+ `knowledge/*` branches. A maintainer reviews the branch and merges via PR.
135
+
136
+ ## Step 8 — Report
137
+
138
+ List exactly what changed (clickable relative paths), and note any ⚠ ELEVATED docs the
139
+ developer approved so they remember those touched senior-owned standards/architecture.
140
+ If Step 7 pushed successfully, include the push confirmation in the report.
141
+
142
+ ---
143
+
144
+ ## Doc templates (write inline; no separate template files)
145
+
146
+ ### feature / client-feature
147
+ ```markdown
148
+ ---
149
+ title: <Title>
150
+ framework: "<1.0|2.0>"
151
+ repo: <repo> # omit for a pure client doc not tied to one repo
152
+ project: <Project>
153
+ client: <shared|client-slug>
154
+ type: <feature|client-feature>
155
+ status: active
156
+ updated: <YYYY-MM-DD>
157
+ owners: [<who>]
158
+ files:
159
+ - <on-disk/path/one>
160
+ related: [] # client-feature: link the shared apps/<repo>/features/<base>.md
161
+ ---
162
+
163
+ ## Summary
164
+ What it does and why.
165
+
166
+ ## Key files / entry points
167
+ The main files and how control flows.
168
+
169
+ ## How it works
170
+ Step-by-step.
171
+
172
+ ## Data model
173
+ Tables/columns touched (if any).
174
+
175
+ ## Client variations
176
+ How behavior differs per client (or "none — uniform").
177
+
178
+ ## Gotchas / known issues
179
+ The non-obvious things future-you will trip on.
180
+
181
+ ## Related docs
182
+ Links.
183
+ ```
184
+
185
+ ### workflow (client business process)
186
+ ```markdown
187
+ ---
188
+ title: <Workflow Name>
189
+ framework: "<1.0|2.0>"
190
+ project: <Project>
191
+ client: <client-slug>
192
+ type: workflow
193
+ status: active
194
+ updated: <YYYY-MM-DD>
195
+ owners: [<who>]
196
+ files: []
197
+ related: []
198
+ ---
199
+
200
+ ## Summary
201
+ The business process and who it serves.
202
+
203
+ ## Steps
204
+ 1. …
205
+
206
+ ## Systems involved
207
+ Apps/repos, integrations, data.
208
+
209
+ ## Edge cases & escalation
210
+ What can go wrong and who handles it.
211
+ ```
212
+
213
+ ### architecture (one per repo) — ⚠ ELEVATED
214
+ ```markdown
215
+ ---
216
+ title: <Repo> Architecture
217
+ framework: "<1.0|2.0>"
218
+ repo: <repo>
219
+ project: <Project>
220
+ client: shared
221
+ type: architecture
222
+ status: active
223
+ updated: <YYYY-MM-DD>
224
+ owners: [<who>]
225
+ files: [<key paths>]
226
+ related: []
227
+ ---
228
+
229
+ ## Summary
230
+ ## <system sections: components, data, flows, key decisions>
231
+ ```
232
+
233
+ ### standard (coding standard) — ⚠ ELEVATED
234
+ ```markdown
235
+ ---
236
+ title: <Backend|Frontend|…> Standards
237
+ framework: "<1.0|2.0>"
238
+ project: <core-project, e.g. _Underscore or Library>
239
+ client: shared
240
+ type: standard
241
+ status: active
242
+ updated: <YYYY-MM-DD>
243
+ owners: [<who>]
244
+ files: []
245
+ related: []
246
+ ---
247
+
248
+ ## <topic sections: naming, structure, DB access, errors, testing, security…>
249
+ ```
250
+
251
+ ## New-repo onboarding (repo not in `registry.json`)
252
+
253
+ Ask **all** — assume nothing (a heuristic may seed a default to confirm):
254
+ 1. Repo name (exact on-disk name). 2. Framework (1.0/2.0). 3. Project name.
255
+ 4. Role (core or app). 5. `dependsOn` repos beyond the framework core (default none).
256
+ 6. Local path on this machine (if not remembered → write a `repo-path-<repo>` memory).
257
+
258
+ Append the entry to `registry.json`, then continue. `validate` will confirm consistency.
259
+
260
+ ---
261
+
262
+ ### After Capture
263
+
264
+ Once you have completed a capture session and confirmed the changes are committed to
265
+ the knowledge base, suggest the following to the developer:
266
+
267
+ > "Session captured successfully. If you're done for today or may not finish this
268
+ > thread in one sitting, run `/session-save` to persist your session state. This
269
+ > records exactly what worked, what failed, what's pending, and your exact next step —
270
+ > so you can resume without losing context, even days later."
271
+
272
+ Provide the suggested command with a name hint:
273
+ ```
274
+ /session-save <suggested-slug-based-on-what-was-worked-on>
275
+ ```
276
+
277
+ For example, if the session was about "ClickUp deploy worker actions", suggest:
278
+ ```
279
+ /session-save clickup-deploy-worker
280
+ ```
281
+
282
+ ### PostToolUse hook auto-validation
283
+
284
+ The `.claude/settings.json` in this repo includes a `PostToolUse` hook that
285
+ automatically runs `node knowledge.js validate` after any file write to `knowledge/`.
286
+ This means:
287
+
288
+ - As each doc is written during the capture step, validation runs immediately.
289
+ - You will see inline output with any `ERROR:` or `OK` messages.
290
+ - If validation fails after a write, address the error before writing the next doc —
291
+ do not proceed to Step 6's explicit `validate` run while errors are outstanding.
292
+ - Step 6's explicit `node knowledge.js validate` call is still required as the final
293
+ gate — the hook fires per-write, but the explicit call confirms global consistency
294
+ after all writes are complete.
@@ -0,0 +1,140 @@
1
+ ---
2
+ name: code-review
3
+ description: PHP-focused code review for TOGA Technology projects. Reviews for SQL injection, XSS, framework pattern violations (App_ vs _underscore), N+1 queries, and coding standards. Trigger when the user says "code-review", "review this file", "check my code", or "review [filename]".
4
+ ---
5
+
6
+ # Code Review Skill
7
+
8
+ PHP-focused code review skill for TOGA Technology projects. Reviews for security vulnerabilities, framework pattern violations, SQL quality, and style issues.
9
+
10
+ ## Usage
11
+
12
+ ```
13
+ /code-review [file-path]
14
+ /code-review src/Controllers/Orders.php
15
+ /code-review # reviews most recently modified PHP files
16
+ ```
17
+
18
+ ---
19
+
20
+ ## Behavior
21
+
22
+ ### Step 1 — Identify files to review
23
+
24
+ If a file path is provided: read that file.
25
+
26
+ If no file path is provided: find the most recently modified PHP files in the session by checking tool-use history for Write/Edit operations on `.php` files. Review up to 3 files.
27
+
28
+ If no PHP files were modified this session: ask the user which file to review.
29
+
30
+ ### Step 2 — Detect framework
31
+
32
+ Read the file's class declarations:
33
+ - Class names starting with `App_` → Framework 1.0
34
+ - Class names with leading `_` or file under a `2.0` path → Framework 2.0
35
+ - Check `knowledge/registry.json` if still ambiguous
36
+
37
+ Load `knowledge/<fw>/standards/backend-php.md` for team-specific rules.
38
+
39
+ ### Step 3 — Security scan (always run first)
40
+
41
+ Check every finding against a concrete failure mode. Only report issues where a specific exploit or data loss scenario can be described.
42
+
43
+ **Critical security issues to find:**
44
+ - SQL injection: user input (`$_GET`, `$_POST`, `$_COOKIE`, function params traceable to user input) concatenated/interpolated into SQL strings
45
+ - XSS: user-supplied data echoed or printed without `htmlspecialchars()`
46
+ - `eval()` or `exec()` on user-controlled strings
47
+ - Raw `$_GET`/`$_POST`/`$_COOKIE` used without validation
48
+ - Passwords stored in plaintext or hashed with MD5/SHA1
49
+ - Sensitive data (passwords, tokens, PII) in log statements
50
+ - File path construction from user input without allowlist
51
+ - Missing `WHERE` clause on `UPDATE` or `DELETE`
52
+
53
+ ### Step 4 — Framework pattern scan
54
+
55
+ **For Framework 1.0 (App_):**
56
+ - Classes missing `App_` prefix
57
+ - Controllers not extending `App_Controller`
58
+ - Models not extending `App_Model`
59
+ - Direct model instantiation with `new` instead of `App_Registry::get()`
60
+ - `snake_case` public method names
61
+
62
+ **For Framework 2.0 (_underscore):**
63
+ - Workers not extending `_Worker` or missing `run()` method
64
+ - Workers called directly instead of via `_Queue::dispatch()`
65
+ - `api2` action methods not returning the standard `{success, data, errors}` envelope
66
+ - Missing error type distinction (retriable vs non-retriable) in workers
67
+
68
+ ### Step 5 — SQL quality scan
69
+
70
+ - N+1: query inside a loop where the query uses a loop variable
71
+ - Unbounded `SELECT` without `LIMIT` on non-lookup tables
72
+ - `SELECT *` instead of named columns (INFO level)
73
+ - Deprecated: `mysql_query()`, `mysql_escape_string()`, `addslashes()` for SQL
74
+
75
+ ### Step 6 — Style scan
76
+
77
+ Only flag style issues with a direct rule citation from `rules/common/coding-style.md`:
78
+ - Bare `catch` or catch-and-ignore
79
+ - Mutable state in catch block without log or rethrow
80
+ - Magic numbers (unexplained literals)
81
+ - Commented-out code
82
+ - Functions with 4+ positional parameters
83
+ - Missing return type declarations on public methods
84
+
85
+ ### Step 7 — Confidence filter
86
+
87
+ Before including any finding in the output, confirm:
88
+ 1. The exact file:line can be cited
89
+ 2. The concrete failure mode (exploit, data loss, wrong behavior) can be described
90
+ 3. It is not a style preference without a rule backing it
91
+
92
+ Remove any finding that fails this filter. It is better to report 2 real issues than 8 vague ones.
93
+
94
+ ### Step 8 — Output
95
+
96
+ Build the findings table. Count by severity. Output the summary.
97
+
98
+ ---
99
+
100
+ ## Output Format
101
+
102
+ ```
103
+ ## Code Review — src/Controllers/Orders.php
104
+ Framework: 2.0 (_underscore)
105
+
106
+ | File:Line | Severity | Issue | Fix |
107
+ |-----------|----------|-------|-----|
108
+ | Orders.php:34 | CRITICAL | SQL injection: `$_POST['status']` interpolated into query string | Use `_Db::select('orders', ['status' => $_POST['status']])` or PDO prepared statement |
109
+ | Orders.php:71 | CRITICAL | Missing WHERE on UPDATE: `_Db::update('orders', $data)` with no condition | Add condition array as third param: `_Db::update('orders', $data, ['id' => $orderId])` |
110
+ | Orders.php:102 | WARNING | Worker called directly: `$w = new _Worker_Notify(); $w->run()` | Dispatch via queue: `_Queue::dispatch('_Worker_Notify', $payload)` |
111
+ | Orders.php:118 | WARNING | N+1 query: `_Db::find('order_items', ['order_id' => $o->id])` inside foreach | Collect IDs, batch with IN clause outside loop |
112
+ | Orders.php:145 | INFO | `SELECT *` — retrieves all columns | Replace with explicit column list to reduce data transfer |
113
+
114
+ **Summary:** 2 critical, 2 warnings, 1 info
115
+
116
+ Critical issues must be fixed before merge.
117
+ Warnings should be fixed before merge.
118
+ Info items are optional improvements.
119
+ ```
120
+
121
+ If zero findings across all categories:
122
+
123
+ ```
124
+ ## Code Review — src/Controllers/Orders.php
125
+ Framework: 2.0 (_underscore)
126
+
127
+ No issues found. All checks passed.
128
+
129
+ Checks run: SQL injection, XSS, eval/exec, input validation, framework patterns,
130
+ worker dispatch, API envelope, SQL quality, error handling, style rules.
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Notes
136
+
137
+ - Never invent findings to appear thorough. "No issues found" is a valid and useful result.
138
+ - If a file is too large to review completely in one pass, state which sections were reviewed and which were not.
139
+ - If the framework cannot be determined, state this and ask before proceeding.
140
+ - For files in the `library` or `_underscore` core repos: flag any change to a base class method signature as a WARNING with a note that dependent repos must be checked.
@@ -0,0 +1,217 @@
1
+ ---
2
+ name: create-elastic-beanstalk
3
+ description: Generates a ready-to-paste AWS CloudShell command that creates a new Elastic Beanstalk environment following True/Agilant conventions. Use this skill whenever the user wants to create, spin up, or provision a new Elastic Beanstalk environment, add an EB environment to an existing application, or asks for the CloudShell command to launch a beanstalk. Trigger immediately even if they just say "make me a new beanstalk for X" or "new EB env in the API app".
4
+ ---
5
+
6
+ # Create Elastic Beanstalk Environment
7
+
8
+ ## What this skill does
9
+
10
+ You interview the user, then output a **single copy-paste CloudShell command** that creates a new
11
+ Elastic Beanstalk *environment* inside an *existing* EB *application*. The command must run as-is
12
+ when pasted into AWS CloudShell — no placeholders left behind, no editing required.
13
+
14
+ You do **not** run any AWS commands yourself (you are not in CloudShell). You gather the answers,
15
+ fill in the proven values below, and print the final command for the developer to paste.
16
+
17
+ ## The core rule: PRODUCTION vs everything else
18
+
19
+ The value of the `ENVIRONMENT` variable decides almost everything. If the user's `ENVIRONMENT`
20
+ value is exactly `production`, use the **PRODUCTION profile**. Any other value
21
+ (`client-alpha`, `qa-beta`, `sandbox-dev`, etc.) uses the **NON-PROD profile**.
22
+
23
+ These two profiles live in **different AWS accounts** with different VPCs, subnets, roles, and
24
+ storage. The developer's CloudShell session must be logged into the matching account — always tell
25
+ them which account to confirm before they paste.
26
+
27
+ ### PRODUCTION profile — AWS account `654654170868`
28
+
29
+ | Setting | Value |
30
+ |---|---|
31
+ | VPC | `vpc-08030daf1c2dad280` |
32
+ | Instance (private) subnets | `subnet-0e135d4093ab60b2f,subnet-0c6579c05a0f51ac6,subnet-096d9f8f0617949ef` |
33
+ | ELB (public) subnets | `subnet-016ceecffa8c484dd,subnet-0a03a9af3536ab3e2,subnet-0f4272cd10edeee8d` |
34
+ | Instance profile | `ElasticBeanstalk-EC2-Instance-Profile` |
35
+ | Service role | `arn:aws:iam::654654170868:role/service-role/aws-elasticbeanstalk-service-role` |
36
+ | Storage | `gp2` (SSD), 10 GB |
37
+ | Load balancer | **Dedicated** application LB (`LoadBalancerIsShared=false`), public-facing |
38
+ | Default instance type | `t4g.large` |
39
+ | Default instance count | Min = Max = `2` |
40
+
41
+ ### NON-PROD profile — AWS account `975050298201`
42
+
43
+ | Setting | Value |
44
+ |---|---|
45
+ | VPC | `vpc-0c5319e7df6f736c5` |
46
+ | Instance (private) subnets | `subnet-0d6acbaf19ee03fa9,subnet-0f5085f369274c305,subnet-0133a6098281928c7` (`true-test-private-web-a/b/c`) |
47
+ | Instance profile | `aws-elasticbeanstalk-ec2-role` |
48
+ | Service role | `arn:aws:iam::975050298201:role/aws-elasticbeanstalk-service-role` |
49
+ | Storage | `standard` (magnetic), 10 GB |
50
+ | Load balancer | **Shared** application LB (`LoadBalancerIsShared=true`) — must pick one (see list) |
51
+ | Default instance type | `t4g.micro` |
52
+ | Default instance count | Min = Max = `1` |
53
+
54
+ > Non-prod uses a **shared** ALB, so do NOT set `ELBScheme`, `ELBSubnets`, or
55
+ > `AssociatePublicIpAddress`. Elastic Beanstalk rejects subnet config on a shared load balancer; it
56
+ > simply attaches a listener rule to the existing ALB.
57
+
58
+ ## Always-true conventions (both profiles)
59
+
60
+ - **Platform:** PHP on Amazon Linux 2023, Apache proxy, **arm64** (`SupportedArchitectures=arm64`,
61
+ `t4g` family). Default solution stack: `64bit Amazon Linux 2023 v4.13.1 running PHP 8.5`.
62
+ - **Key pair:** `true-aws-infrastructure-production`.
63
+ - **Deployments:** `AllAtOnce` — **always**, no exceptions.
64
+ - **No real autoscaling:** AWS won't let you disable it, so neuter the trigger — watch
65
+ `CPUUtilization` with `LowerThreshold=2000000` and `UpperThreshold=6000000` so it never breaches.
66
+ Always use `Unit=Percent`. Set Min = Max instance count so the group size is pinned.
67
+ - **Instances** always go in the **private** subnets; load balancers in **public** subnets.
68
+ - **On-Demand only** — always default to On-Demand instances (`EnableSpot=false`), never Spot.
69
+
70
+ ## Interview the user (ask before generating anything)
71
+
72
+ Ask these together in one message. Don't generate the command until you have the answers.
73
+
74
+ 1. **`ENVIRONMENT` value** — what string goes in the `ENVIRONMENT` variable? (e.g. `production`,
75
+ `client-delta`, `qa-hotfix`). This selects the profile. Treat exactly `production` as PRODUCTION.
76
+
77
+ 2. **EB application** — which existing application? It must already exist (this skill never creates
78
+ the application). Known applications: `SAML`, `talos-backend`, `TOGA Technology`, `API`,
79
+ `TOGaCommerce`, `TOGaIQ`, `Worker`. If unsure, have them run:
80
+ `aws elasticbeanstalk describe-applications --query 'Applications[].ApplicationName' --output table`
81
+
82
+ 3. **Environment name** — the name for the new environment (e.g. `api-client-delta`). Lowercase,
83
+ hyphenated, ≤ 40 chars.
84
+
85
+ 4. **Shared ALB (NON-PROD only)** — which shared ALB should it attach to? Ask for the ALB **name**;
86
+ the generated command resolves the ARN at runtime so it can't go stale. Known shared ALBs in
87
+ account `975050298201` (`describe-load-balancers` to refresh):
88
+ `true-alb-sandbox-dev`, `true-alb-sandbox-client`, `true-alb-client-alpha`,
89
+ `true-alb-client-beta`, `true-alb-client-gamma`, `true-alb-qa-alpha`, `true-alb-qa-beta`,
90
+ `true-alb-qa-gamma`, `true-alb-qa-hotfix`, `true-alb-qa-task`, `true-alb-qc-alpha`,
91
+ `true-alb-qc-beta`, `true-alb-qc-gamma`, `true-alb-qc-hotfix`, `true-alb-qc-performance`,
92
+ `true-alb-qc-security`, `true-alb-qc-task`.
93
+
94
+ 5. **Instance type** — confirm or change. Default `t4g.micro` (non-prod) / `t4g.large` (prod). Must
95
+ be arm64 `t4g` family; `t4g.micro` is the floor.
96
+
97
+ 6. **Instance count** — confirm or change. Default Min = Max = `1` (non-prod) / `2` (prod). It's
98
+ pinned (no scaling), so Min and Max are set equal.
99
+
100
+ 7. **PHP version** *(optional)* — default `8.5`. Other current AL2023 options: `8.1`, `8.2`, `8.3`,
101
+ `8.4`. Maps to solution stack `64bit Amazon Linux 2023 v4.13.1 running PHP <ver>`.
102
+
103
+ 8. **CNAME prefix** *(optional)* — defaults to the environment name.
104
+
105
+ ## Generating the command
106
+
107
+ Substitute every value at generation time so the printed command has no placeholders. Build the
108
+ option settings as a JSON heredoc, then call `create-environment`.
109
+
110
+ Before the command, print a one-line **account check** banner, e.g.:
111
+ > ⚠️ Confirm your CloudShell is logged into account **975050298201** (non-prod) before pasting.
112
+
113
+ ### NON-PROD template (shared ALB)
114
+
115
+ ```bash
116
+ # Target account: 975050298201 | App: <APP> | Env: <ENV_NAME> | ENVIRONMENT=<ENV_VALUE>
117
+ SHARED_ALB_ARN=$(aws elbv2 describe-load-balancers \
118
+ --names "<SHARED_ALB_NAME>" \
119
+ --query 'LoadBalancers[0].LoadBalancerArn' --output text)
120
+
121
+ cat > /tmp/eb-options.json <<EOF
122
+ [
123
+ {"Namespace":"aws:autoscaling:asg","OptionName":"MinSize","Value":"<COUNT>"},
124
+ {"Namespace":"aws:autoscaling:asg","OptionName":"MaxSize","Value":"<COUNT>"},
125
+ {"Namespace":"aws:ec2:instances","OptionName":"InstanceTypes","Value":"<INSTANCE_TYPE>"},
126
+ {"Namespace":"aws:ec2:instances","OptionName":"SupportedArchitectures","Value":"arm64"},
127
+ {"Namespace":"aws:ec2:instances","OptionName":"EnableSpot","Value":"false"},
128
+ {"Namespace":"aws:autoscaling:launchconfiguration","OptionName":"IamInstanceProfile","Value":"aws-elasticbeanstalk-ec2-role"},
129
+ {"Namespace":"aws:autoscaling:launchconfiguration","OptionName":"EC2KeyName","Value":"true-aws-infrastructure-production"},
130
+ {"Namespace":"aws:autoscaling:launchconfiguration","OptionName":"RootVolumeType","Value":"standard"},
131
+ {"Namespace":"aws:autoscaling:launchconfiguration","OptionName":"RootVolumeSize","Value":"10"},
132
+ {"Namespace":"aws:autoscaling:launchconfiguration","OptionName":"DisableIMDSv1","Value":"true"},
133
+ {"Namespace":"aws:ec2:vpc","OptionName":"VPCId","Value":"vpc-0c5319e7df6f736c5"},
134
+ {"Namespace":"aws:ec2:vpc","OptionName":"Subnets","Value":"subnet-0d6acbaf19ee03fa9,subnet-0f5085f369274c305,subnet-0133a6098281928c7"},
135
+ {"Namespace":"aws:elasticbeanstalk:environment","OptionName":"LoadBalancerType","Value":"application"},
136
+ {"Namespace":"aws:elasticbeanstalk:environment","OptionName":"LoadBalancerIsShared","Value":"true"},
137
+ {"Namespace":"aws:elasticbeanstalk:environment","OptionName":"ServiceRole","Value":"arn:aws:iam::975050298201:role/aws-elasticbeanstalk-service-role"},
138
+ {"Namespace":"aws:elbv2:loadbalancer","OptionName":"SharedLoadBalancer","Value":"${SHARED_ALB_ARN}"},
139
+ {"Namespace":"aws:elasticbeanstalk:command","OptionName":"DeploymentPolicy","Value":"AllAtOnce"},
140
+ {"Namespace":"aws:elasticbeanstalk:environment:proxy","OptionName":"ProxyServer","Value":"apache"},
141
+ {"Namespace":"aws:autoscaling:trigger","OptionName":"MeasureName","Value":"CPUUtilization"},
142
+ {"Namespace":"aws:autoscaling:trigger","OptionName":"Statistic","Value":"Average"},
143
+ {"Namespace":"aws:autoscaling:trigger","OptionName":"Unit","Value":"Percent"},
144
+ {"Namespace":"aws:autoscaling:trigger","OptionName":"LowerThreshold","Value":"2000000"},
145
+ {"Namespace":"aws:autoscaling:trigger","OptionName":"UpperThreshold","Value":"6000000"},
146
+ {"Namespace":"aws:autoscaling:trigger","OptionName":"LowerBreachScaleIncrement","Value":"-1"},
147
+ {"Namespace":"aws:autoscaling:trigger","OptionName":"UpperBreachScaleIncrement","Value":"1"},
148
+ {"Namespace":"aws:autoscaling:trigger","OptionName":"BreachDuration","Value":"5"},
149
+ {"Namespace":"aws:autoscaling:trigger","OptionName":"Period","Value":"5"},
150
+ {"Namespace":"aws:autoscaling:trigger","OptionName":"EvaluationPeriods","Value":"1"},
151
+ {"Namespace":"aws:elasticbeanstalk:application:environment","OptionName":"ENVIRONMENT","Value":"<ENV_VALUE>"}
152
+ ]
153
+ EOF
154
+
155
+ aws elasticbeanstalk create-environment \
156
+ --application-name "<APP>" \
157
+ --environment-name "<ENV_NAME>" \
158
+ --cname-prefix "<CNAME_PREFIX>" \
159
+ --solution-stack-name "64bit Amazon Linux 2023 v4.13.1 running PHP <PHP_VER>" \
160
+ --option-settings file:///tmp/eb-options.json
161
+ ```
162
+
163
+ ### PRODUCTION template (dedicated public ALB)
164
+
165
+ Same shape, but in account `654654170868`, with the dedicated-LB differences:
166
+
167
+ - Drop the `SHARED_ALB_ARN` lookup and the `aws:elbv2:loadbalancer SharedLoadBalancer` line.
168
+ - `LoadBalancerIsShared` → `false`.
169
+ - `IamInstanceProfile` → `ElasticBeanstalk-EC2-Instance-Profile`.
170
+ - `ServiceRole` → `arn:aws:iam::654654170868:role/service-role/aws-elasticbeanstalk-service-role`.
171
+ - `RootVolumeType` → `gp2`.
172
+ - `VPCId` → `vpc-08030daf1c2dad280`; `Subnets` → the three prod private subnets.
173
+ - Add the public-facing LB lines:
174
+ ```
175
+ {"Namespace":"aws:ec2:vpc","OptionName":"ELBScheme","Value":"public"},
176
+ {"Namespace":"aws:ec2:vpc","OptionName":"ELBSubnets","Value":"subnet-016ceecffa8c484dd,subnet-0a03a9af3536ab3e2,subnet-0f4272cd10edeee8d"},
177
+ {"Namespace":"aws:ec2:vpc","OptionName":"AssociatePublicIpAddress","Value":"false"},
178
+ ```
179
+ - Defaults: `InstanceTypes=t4g.large`, count `2`.
180
+ - Everything else identical: AllAtOnce, `Unit=Percent` trigger 2000000–6000000, `EnableSpot=false`,
181
+ arm64, Apache, key pair, 10 GB root volume.
182
+
183
+ ## After printing the command
184
+
185
+ Tell the developer, concisely:
186
+
187
+ 1. **Confirm the account** — CloudShell must be in `654654170868` (prod) or `975050298201`
188
+ (non-prod). Paste fails or misbehaves if they're in the wrong account.
189
+ 2. The application must already exist; this only creates the environment.
190
+ 3. Watch it come up: `aws elasticbeanstalk describe-environments --environment-names "<ENV_NAME>" --query 'Environments[0].{Status:Status,Health:Health,CNAME:CNAME}' --output table`
191
+ 4. If EB complains about a missing listener rule on a shared ALB, the env still creates; the rule is
192
+ added automatically once the environment is `Ready`.
193
+
194
+ ## Reviewing / cloning an existing environment
195
+
196
+ To copy settings from a known-good environment, dump its full config (this is how this skill's
197
+ values were sourced):
198
+
199
+ ```bash
200
+ aws elasticbeanstalk describe-configuration-settings \
201
+ --application-name "<APP>" --environment-name "<EXISTING_ENV>" \
202
+ --query 'ConfigurationSettings[0].OptionSettings[].{NS:Namespace,Opt:OptionName,Val:Value}' \
203
+ --output table
204
+ ```
205
+
206
+ If the user is targeting an account other than the two above, ask them to run that command (plus
207
+ `aws ec2 describe-subnets` and `aws elbv2 describe-load-balancers`) and paste the output so you can
208
+ build a matching profile rather than guessing.
209
+
210
+ ## Conventions baked in (don't silently change these)
211
+
212
+ - All-at-once deploys, arm64/t4g, Apache, private-subnet instances, public-subnet LBs, the
213
+ 2000000–6000000 never-trigger CPU hack (`Unit=Percent`), pinned Min=Max instance count, the
214
+ `true-aws-infrastructure-production` key pair, 10 GB root volume (SSD `gp2` prod / magnetic
215
+ `standard` non-prod), On-Demand instances.
216
+ - If the user explicitly asks to deviate (e.g. enable Spot, change storage), honor it but call out
217
+ that it departs from the standard.