Hexa Hub

Skills and tools (recipes) for Hexa. In Hexa open Library, set the address to https://hexahub.cerberus-srv.de/index.json and press Refresh. Every pack is shown to you in full before it is installed, is checked against the sha256 below, is plain text (never code that runs on install) and starts switched off.

Ansible Skill Infrastructure as code

Write, lint, dry-run and run Ansible playbooks, roles and inventories safely.

id ansible · version 1.0.0 · 3.9 KB · sha256 de93244a827a… · pack (JSON)

Read the skill
---
name: ansible
description: Write, lint, dry-run and run Ansible playbooks, roles and inventories safely.
title: Ansible
icon: tabler:brand-ansible
category: Infrastructure as code
triggers: ansible, playbook, role, inventory, group_vars, handler, ansible-lint, galaxy, jinja
markers: ansible, ansible-lint
recipes: ansible.syntax-check, ansible.lint, ansible.inventory-list, ansible.check, ansible.run, help.ansible-doc
related: terraform, puppet
---

# Ansible

Ansible does not run on Windows itself. On a Windows PC run the recipes where Ansible lives: `on: "wsl:<name>"` or `on: "ssh:<name>"` (hosts are set up in Settings, Hosts). If the recipe says the program is missing, use `toolchain`.

**Check or review request**: read the playbook or role, run `ansible.syntax-check` and `ansible.lint`, then answer. Do not run the dry run or the playbook for a review. If Ansible is not installed here, say so and review the code by reading it.

## Workflow for a change
1. **Look first.** Find the playbook, the role and the inventory it targets (`find_code`, `list_dir`). Follow the layout in use: `inventories/<env>/`, `group_vars/`, `roles/<name>/{tasks,handlers,defaults,vars,templates,files,meta}`.
2. Edit the role or playbook.
3. `ansible.syntax-check`, then `ansible.lint`. Fix everything lint reports unless the user's existing code clearly ignores that rule.
4. `ansible.check` (dry run, `--check --diff`) with `limit` set to one host first. **Show the user what would change.** Tasks that cannot run in check mode are skipped, so say what the dry run could not tell.
5. Only if the user asks to run it: `ansible.run` with the same playbook, inventory and limit. It always asks, works only right after the check on unchanged files, and is blocked for prod inventories. Roll out to one host, look at the result, then widen `limit`.

Example: `run_recipe {"recipe":"ansible.check","args":{"playbook":"site.yml","inventory":"inventories/test","limit":"web01"},"on":"wsl:ubuntu"}`

## Write idempotent tasks
- Use the module for the job, with its fully qualified name (`ansible.builtin.copy`, `ansible.builtin.template`, `ansible.posix.firewalld`). Look up arguments for the installed version with `help.ansible-doc` (module name); never invent arguments.
- `command`/`shell` only when no module exists, and then with `creates:` or `changed_when:` so a second run reports no change. A second dry run after a run must show zero changes.
- Every task has a `name`. Restart services with handlers (`notify:`), not tasks. Use `become` on the task or play that needs it, not for everything.
- Variables: role defaults in `defaults/main.yml` (overridable), constants in `vars/`, environment values in `group_vars/<env>`. Prefix variable names with the role name.
- Booleans and modes as the right type: `mode: "0644"` (string), `enabled: true`. A value starting with `{{` must be quoted: `path: "{{ base_dir }}/app"`.
- `when:` takes a bare expression (no braces). `loop:` instead of `with_items`.

## Secrets
Never write passwords into playbooks, vars files or templates. Use `ansible-vault` encrypted files and reference the variable by name; ask the user to create the vault content. Add `no_log: true` to tasks that handle secrets. Hexa's secret handles are for files you write for the user's machine, not for files that go into version control.

## Windows targets
Use the `ansible.windows` and `community.windows` collections over WinRM or SSH; module names differ (`ansible.windows.win_service`). Check with `help.ansible-doc`.

## Report
Say: what changed in the code, lint result, what the dry run said (hosts, tasks that would change) and whether anything was actually run.

Azure administration Skill Cloud

Inspect and manage Azure: subscriptions, resource groups, networking, AKS, storage, SQL Managed Instance, Entra ID and RBAC, preferably through Terraform.

id azure-admin · version 1.0.0 · 3.9 KB · sha256 ee9e91403021… · pack (JSON)

Read the skill
---
name: azure-admin
description: Inspect and manage Azure: subscriptions, resource groups, networking, AKS, storage, SQL Managed Instance, Entra ID and RBAC, preferably through Terraform.
title: Azure administration
icon: tabler:brand-azure
category: Cloud
triggers: azure, az cli, subscription, resource group, aks, entra, rbac, role assignment, key vault, storage account, managed instance, tenant, arm, bicep, log analytics
markers: az
recipes: az.account-show, az.list, az.show, help.az, terraform.plan
related: terraform, kubernetes-helm, sql-server-liquibase
---

# Azure administration

## Always start here
1. `az.account-show`: which tenant and **subscription** are active. Tell the user and continue only if it is the intended one. Production subscriptions: read only.
2. Look before you change: `az.list` (group: `group`, `vm`, `aks`, `storage` + subgroup `account`, `sql` + subgroup `mi`, `network` + subgroup `vnet`, `keyvault`, ...) and `az.show` for one resource.
3. Unsure how a command works for the installed CLI version? `help.az` with the group and command (for example group `sql`, command `mi`).

Example: `run_recipe {"recipe":"az.list","args":{"group":"aks","resource_group":"rg-shop-test"}}`

## Changes go through code
Create and change Azure resources with Terraform (the `terraform` skill), reviewed with `terraform.plan`, not with ad-hoc `az ... create/delete/update` commands: the code is the record of what exists. If the user wants a one-off change, tell them the exact `az` command and explain what it does and whether it can be undone; do not run mutating Azure commands yourself.

## Reading the picture
- **Resource groups** hold related resources and are the usual deletion and permission boundary. Names and tags show owner and environment.
- **Networking:** a VNet has subnets; NSGs filter traffic by priority (lowest number first); private endpoints and DNS zones (`privatelink...`) are the usual cause of "cannot connect" to PaaS services from inside the network.
- **AKS:** cluster, node pools (system and user), managed identity; use the `kubernetes-helm` skill for what runs inside. Credentials come from `az aks get-credentials` (the user runs it).
- **Storage accounts:** public access, firewall rules and shared-key access are the settings to check first; prefer Entra ID authentication.
- **SQL Managed Instance:** lives in its own subnet with a route table and NSG that Azure manages; connectivity problems are almost always networking or DNS. Use the `sql-server-liquibase` skill for queries.

## Identity and access (Entra ID, RBAC)
- Azure RBAC role assignments are scope + role + principal. To answer "who can do what": list role assignments at the scope (`az role assignment list --scope ...` is read only; ask the user to run it if no recipe covers it) and explain inherited assignments from management group, subscription and resource group.
- Least privilege: use the narrowest built-in role at the narrowest scope; managed identities instead of service-principal secrets; no `Owner`/`Contributor` at subscription level for apps.
- Never create, rotate or print secrets, keys or tokens. Key Vault values are read by the application's identity, not copied into code.

## Costs and cleanup
For cost questions, list resources and sizes first (`az.list`, `az.show`) and reason from SKU, size and count; say that real spend is in Cost Management and that you only have the configuration. Never delete resources. Say what looks unused and let the user decide.

## Report
Say which subscription you looked at, what you found, and what you did not or could not check.

Docker and Compose Skill Containers

Write and debug Dockerfiles and Docker Compose files, build images and read container logs.

id docker-compose · version 1.0.0 · 3.4 KB · sha256 46d5562ed021… · pack (JSON)

Read the skill
---
name: docker-compose
description: Write and debug Dockerfiles and Docker Compose files, build images and read container logs.
title: Docker and Compose
icon: tabler:brand-docker
category: Containers
triggers: docker, dockerfile, compose, container, image, volume, entrypoint, docker-compose
markers: docker
recipes: docker.ps, docker.logs, docker.compose-config, docker.build, help.docker
related: kubernetes-helm, gitlab-ci
---

# Docker and Compose

## Workflow
1. Read the existing `Dockerfile`, `compose.yaml` and `.dockerignore` first and follow their style.
2. Edit. For Compose: `docker.compose-config` validates the file and shows the resolved result (variables filled in, anchors expanded). Fix every error it reports.
3. To build: `docker.build` (asks; it creates an image on this PC). Read the failing step from the output; fix that step only.
4. To look at what is running: `docker.ps`, then `docker.logs` for one container. Say what the logs show; do not guess.

Example: `run_recipe {"recipe":"docker.logs","args":{"container":"shop-web-1"}}`

## Dockerfile habits
- Small, pinned base image (`python:3.12-slim`, not `latest`). Multi-stage builds: build in one stage, copy only the result into a small runtime stage.
- Order for the cache: copy dependency files first (`package*.json`, `composer.json`, `requirements.txt`), install, then copy the rest, so code changes do not reinstall everything.
- Run as a non-root `USER`. One process per container; `CMD`/`ENTRYPOINT` in exec form (`["node","server.js"]`) so signals reach the app.
- `.dockerignore` for `.git`, `node_modules`, build output and `.env`. **Never put secrets in the image**: not in `ENV`, `ARG` or a copied file. Use BuildKit secrets (`RUN --mount=type=secret`) at build time and environment or mounted secrets at run time.
- `HEALTHCHECK` when the app has a status endpoint.

## Compose habits
- Use named volumes for data, bind mounts only for development code. Do not publish database ports to all interfaces (`127.0.0.1:5432:5432`).
- `depends_on` with `condition: service_healthy` and a `healthcheck` when startup order matters; it does not wait for readiness otherwise.
- Configuration through `environment:` or an `env_file` that is not committed. Keep `compose.yaml` generic and put development overrides in `compose.override.yaml`.
- Service names are DNS names on the network: an app connects to `db`, not `localhost`.

## Typical problems
| Symptom | Check |
|---|---|
| Container exits at once | `docker.logs`: the last lines; wrong CMD, missing env var, file not copied |
| Port already in use | another container or program holds the host port; change the left side of `ports:` |
| "No such file" in build | the path is relative to the build context, and `.dockerignore` may exclude it |
| Changes to code not visible | image not rebuilt, or a bind mount hides the copied files |
| Cannot connect to the other service | wrong host name (use the service name), service not ready, different network |

## Report
Say what you changed, whether the compose file validated, what the build or logs showed, and what you did not run.

Frontend: HTML, CSS, Tailwind, JavaScript Skill Development

Build and fix frontends: HTML, CSS, Tailwind CSS (v3 and v4 differ), JavaScript and TypeScript, Vite, Alpine, Blade, Vue and React components.

id frontend-tailwind-js · version 1.0.0 · 4.3 KB · sha256 59b1d957a42c… · pack (JSON)

Read the skill
---
name: frontend-tailwind-js
description: Build and fix frontends: HTML, CSS, Tailwind CSS (v3 and v4 differ), JavaScript and TypeScript, Vite, Alpine, Blade, Vue and React components.
title: Frontend: HTML, CSS, Tailwind, JavaScript
icon: tabler:brand-tailwind
category: Development
triggers: css, tailwind, html, javascript, typescript, vite, alpine, button, layout, responsive, flexbox, grid, component, npm, eslint, frontend, ui, style, class
markers: tailwind
recipes: check.eslint, check.tsc, deps.npm-ci, npm.build, npm.test
related: laravel-php
---

# Frontend: HTML, CSS, Tailwind, JavaScript

## Find out what the project uses first
Read `package.json` and the lockfile: the **Tailwind version** (`tailwindcss`), the bundler (Vite), the framework (Vue, React, Alpine, Livewire, none) and the scripts (`dev`, `build`, `test`). Follow what is there. For a Laravel project the frontend lives in `resources/` (`css/app.css`, `js/app.js`, Blade views).

## Tailwind: v3 and v4 are different
| | v3 | v4 |
|---|---|---|
| CSS entry | `@tailwind base; @tailwind components; @tailwind utilities;` | `@import "tailwindcss";` |
| Configuration | `tailwind.config.js` (`content`, `theme.extend`) | in CSS: `@theme { --color-brand: #5b21b6; }`; a config file is optional |
| Content detection | `content: [...]` globs | automatic |
| Vite | PostCSS plugin | `@tailwindcss/vite` plugin |
Which one applies? Look at the installed version in `package.json`; if the CSS has `@import "tailwindcss"` it is v4. **Do not mix them.** If unsure, read the existing CSS and config and copy that style.

Using Tailwind well:
- Utility classes in the markup (`flex items-center gap-4 rounded-lg p-4`); responsive prefixes mobile first (`md:flex`, `lg:grid-cols-3`); states (`hover:`, `focus-visible:`, `disabled:`, `dark:`).
- Repeated patterns become a component (Blade component, Vue/React component) rather than `@apply` everywhere. Do not build class names from variables (`bg-${color}-500`): Tailwind only sees complete class names, so write them out or map to full strings.
- Spacing and colours from the theme, not arbitrary values, unless the design needs one.

## CSS without a framework
Mobile-first media queries; flexbox for one dimension and grid for two; `rem` for type and spacing; custom properties for colours; `min()`/`clamp()` for fluid sizes; logical properties (`margin-inline`). Do not fix layout with fixed widths and `!important`. Check at 320 px wide and at desktop width.

## Accessibility (always)
Semantic elements (`button`, `nav`, `main`, `label`), every input has a label, visible focus, text contrast at least 4.5:1, images have `alt`, buttons that only show an icon get `aria-label`, never remove outlines without a replacement, everything works with the keyboard.

## JavaScript and TypeScript
- `const`/`let`, no globals, `async/await` with `try/catch` at the boundary, `fetch` with a check of `response.ok`. Never put user data into `innerHTML`; use `textContent` or the framework's escaping.
- TypeScript: strict mode, no `any` without a reason, types for data coming from the network are validated at runtime (zod or similar), not just asserted.
- Alpine: state in `x-data`, events `@click`, show/hide with `x-show`; keep logic small, otherwise move it into a function.
- Vue/React: keep components small; state as low as possible; keys on list items; no side effects while rendering.

## Checks (run them, report them)
Run `check.tsc` for TypeScript projects (the workspace folder must hold the `tsconfig.json`), `check.eslint` (`target` file or folder), `npm.test` if the project has tests, and `npm.build` to prove the build works (both ask first). `deps.npm-ci` installs dependencies from the lockfile (asks); never add or upgrade packages unless the user asks. Say which checks you ran and which you could not.

You cannot see the rendered page. When the user asks about appearance, reason from the HTML and CSS, say that you could not view it, and ask the user to look at the result.

GitLab CI/CD Skill CI/CD

Write, validate and debug GitLab CI/CD pipelines (.gitlab-ci.yml): stages, jobs, rules, artifacts, environments and deployments.

id gitlab-ci · version 1.0.0 · 3.4 KB · sha256 f89b22690d6f… · pack (JSON)

Read the skill
---
name: gitlab-ci
description: Write, validate and debug GitLab CI/CD pipelines (.gitlab-ci.yml): stages, jobs, rules, artifacts, environments and deployments.
title: GitLab CI/CD
icon: tabler:brand-gitlab
category: CI/CD
triggers: gitlab, gitlab-ci, pipeline, ci/cd, runner, stage, artifacts, glab, merge request, .gitlab-ci.yml
markers: glab, gitlab-ci
recipes: gitlab.ci-lint, gitlab.pipeline-status, check.yamllint, git.status, git.diff, git.log
related: docker-compose, terraform, ansible
---

# GitLab CI/CD

## Workflow
1. Read `.gitlab-ci.yml` and every file it `include`s (the code map lists them). Follow the existing stage names and job naming.
2. Edit. Validate with `gitlab.ci-lint` (asks GitLab itself, needs `glab` logged in) and `check.yamllint` for plain YAML mistakes.
3. To see what happened on a branch: `gitlab.pipeline-status`; for failed jobs read the job log the user pastes or the GitLab page they point to.
4. Say what changed and what the lint said. A pipeline only proves itself when it runs on GitLab; say that you could not run it.

Example: `run_recipe {"recipe":"gitlab.ci-lint","args":{}}`

## Structure
```yaml
stages: [build, test, deploy]
default:
  image: alpine:3.20
build-app:
  stage: build
  script: [make build]
  artifacts: { paths: [dist/], expire_in: 1 week }
test-app:
  stage: test
  needs: [build-app]
  script: [make test]
deploy-test:
  stage: deploy
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
  environment: test
  script: [./deploy.sh test]
```

## Habits
- **`rules:` not `only:`/`except:`**; never mix them in one job. Typical rules: `if: $CI_PIPELINE_SOURCE == "merge_request_event"`, `if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH`.
- `needs:` lets a job start as soon as its inputs exist; `artifacts` pass files between stages; `cache` (keyed by lockfile) speeds up dependency installs and is not for passing results.
- Deployments: `environment:` set, production jobs `when: manual` and limited to the default branch or protected tags. Use `resource_group:` so two deploys to one environment never run together.
- Reuse with `extends:`, `include:` (local, project, template) and hidden jobs (`.base:`); `!reference [.job, script]` to reuse part of a job.
- A `script` line containing `: ` must be quoted or use a block (`- |`), otherwise YAML reads a mapping.
- Pin images and tool versions. Set `interruptible: true` on tests so new pushes cancel old pipelines.

## Secrets
Never write tokens or passwords in the file. They are **CI/CD variables** (masked, and protected for production), referenced as `$NAME`. Tell the user which variables the job needs and where to set them (Settings, CI/CD, Variables). Do not echo variables in scripts.

## Typical failures
| Symptom | Cause |
|---|---|
| "jobs:x config should contain either only/except or rules" | both used in one job |
| Job does not start | `rules` evaluate to nothing for this branch, or the runner tags do not match |
| "No such file" in a later stage | the file was not listed in `artifacts:paths` or expired |
| Variable empty | variable is protected and the branch is not, or the name differs |

IaC overview: Ansible, Terraform, Puppet Skill Infrastructure as code

Infrastructure as code with Ansible, Terraform (and providers) and Puppet: writing, validating and safely applying changes. Use for playbooks, roles, modules, manifests, HCL.

id iac-ansible-terraform-puppet · version 1.0.0 · 3.0 KB · sha256 262321b7cd94… · pack (JSON)

Read the skill
---
name: iac-ansible-terraform-puppet
description: Infrastructure as code with Ansible, Terraform (and providers) and Puppet: writing, validating and safely applying changes. Use for playbooks, roles, modules, manifests, HCL.
title: IaC overview: Ansible, Terraform, Puppet
icon: tabler:server-cog
category: Infrastructure as code
---

# Infrastructure as code

Universal rules: idempotent changes, version-controlled, secrets never in plain text, **validate and preview before
applying**, and never apply to production without showing the user the preview first. Versions matter: ask which
version/provider/OS if the answer depends on it, and check the official docs (`devtools__web_search` topic `ansible`,
`terraform`, `puppet`).

## Ansible
- Use modules, not `shell`/`command`, so tasks are idempotent. If you must use `command`, add `creates:`/`changed_when:`.
- Use fully qualified names (`ansible.builtin.copy`, `ansible.posix.firewalld`). Check module args in docs.ansible.com.
- Preview: `ansible-playbook site.yml --syntax-check`, then `--check --diff`, then the real run (with `--limit` first).
- Secrets with `ansible-vault`; never log them (`no_log: true`). Handlers for restarts. Quote YAML values that could parse
  as booleans or numbers (`"yes"`, `"0644"` as a string mode). Prefer `become` at task/play level, not root SSH.
- Layout: roles with `defaults/` (overridable) vs `vars/` (fixed). Lint with `ansible-lint`.

## Terraform
- Always `terraform fmt`, `terraform validate`, then `terraform plan -out=plan.tfplan`; show the plan summary
  (adds/changes/destroys) and highlight any destroy or replace before `apply`.
- Pin provider and Terraform versions (`required_providers`, `required_version`) and commit `.terraform.lock.hcl`.
- State holds secrets: remote backend with locking and encryption; never commit state or `*.tfvars` with secrets.
- `for_each` over `count` for things with identity; use `moved` blocks to refactor without recreating; avoid
  `terraform taint`/manual state edits unless asked. `lifecycle { prevent_destroy = true }` for critical resources.
- Check resource arguments in the provider docs on registry.terraform.io for the pinned version; don't guess attributes.

## Puppet
- `puppet parser validate`, `puppet-lint`, then `puppet agent -t --noop` to preview, then apply.
- Data in Hiera, logic in profiles, roles compose profiles (roles/profiles pattern). Keep modules small.
- Resources must be idempotent. `exec` needs `creates`, `unless` or `onlyif`; prefer native types.
- Mind resource ordering (`require`, `before`, `notify`, `->`); avoid duplicate declarations; test in a separate environment.

Kubernetes and Helm Skill Containers

Inspect, debug and change Kubernetes clusters and manifests, and write Helm charts, including GitOps (Argo CD) setups.

id kubernetes-helm · version 1.0.0 · 4.1 KB · sha256 a727d543af7d… · pack (JSON)

Read the skill
---
name: kubernetes-helm
description: Inspect, debug and change Kubernetes clusters and manifests, and write Helm charts, including GitOps (Argo CD) setups.
title: Kubernetes and Helm
icon: tabler:ship
category: Containers
triggers: kubernetes, k8s, kubectl, helm, chart, pod, deployment, ingress, namespace, argocd, argo, kustomize, crashloopbackoff, imagepullbackoff
markers: kubectl, helm
recipes: kubectl.get, kubectl.describe, kubectl.logs, kubectl.diff, kubectl.apply, helm.lint, helm.template, help.kubectl-explain, help.helm
related: docker-compose, gitlab-ci
check: Chart.yaml => helm.lint chart=$dir
---

# Kubernetes and Helm

## First: which cluster?
Every kubectl recipe takes `context`. Ask or check which context is meant; never assume the current one is a test cluster. A context or namespace with `prod` in its name is prod: reading is fine, changes are blocked unless the user unlocked prod.

## Debugging a workload (read-only, no approval)
1. `kubectl.get` resource `pods`, with `namespace`: look at STATUS and RESTARTS.
2. `kubectl.describe` the pod: read the **Events** at the bottom first.
3. `kubectl.logs` for the pod (and `container` if there are several).

| Status | Usual cause | Look at |
|---|---|---|
| ImagePullBackOff / ErrImagePull | wrong image name or tag, no pull secret | describe: the pull error text |
| CrashLoopBackOff | the app exits at start | logs; config, env, missing secret |
| Pending | no node fits: resources, taints, volume not bound | describe Events: `FailedScheduling` or the PVC |
| OOMKilled | memory limit too low | describe: Last State; raise the limit |
| Running but not ready | readiness probe fails | describe: probe; logs |

Say what the evidence shows and what you could not see; do not guess a cause that the events do not support.

**Check or review request**: read the manifest or chart, run `helm.lint` or `kubectl.diff` only if the user wants it compared with the cluster, then answer. Never apply for a review.

## Changing manifests
1. Find the manifest or chart (`find_code`). If **Argo CD or Flux** manages the app, change the Git repository, not the cluster: a direct apply is reverted on the next sync.
2. Edit. Look up field names for the cluster's API version with `help.kubectl-explain` (for example `deployment.spec.strategy`); do not invent fields.
3. For charts: `helm.lint`, then `helm.template` to see the rendered manifests. For plain manifests: `kubectl.diff`.
4. **Show the user the diff.** Only if asked: `kubectl.apply` (same file, namespace and context as the diff). It always asks.

Example: `run_recipe {"recipe":"kubectl.diff","args":{"file":"k8s/web.yaml","namespace":"shop","context":"test-aks"}}`

## Manifest habits
- Always set `resources.requests` and `limits`, `readinessProbe` and `livenessProbe`, a non-root `securityContext`, and an explicit `namespace`.
- Labels and selectors must match (`spec.selector.matchLabels` equals the pod template labels), and a Service selector must match the pod labels: a mismatch shows as a Service with no endpoints.
- Pin image tags (never `latest`); secrets come from `Secret` objects or an external secret store, never from the manifest in Git.
- Deployments: set a rollout strategy and `replicas` >= 2 for anything users depend on; use a PodDisruptionBudget.

## Helm
- Values: defaults in `values.yaml`, environment overrides in `values-<env>.yaml`; read the template to see which values exist.
- Quote strings that could parse as numbers or booleans; use `{{- ... }}` to control whitespace; `required` for mandatory values; `toYaml | nindent N` for blocks.
- `helm.template` must succeed and the output must pass `kubectl.diff` before anyone upgrades a release.

## Report
Say: what you looked at, the finding or the diff, what is still unknown, and whether anything was applied.

Laravel and PHP Skill Development

Build and change Laravel and PHP applications: routes, controllers, Eloquent, migrations, Blade, authentication, queues, tests and code style. Version aware.

id laravel-php · version 1.0.0 · 4.6 KB · sha256 cc2a0ef4abbd… · pack (JSON)

Read the skill
---
name: laravel-php
description: Build and change Laravel and PHP applications: routes, controllers, Eloquent, migrations, Blade, authentication, queues, tests and code style. Version aware.
title: Laravel and PHP
icon: tabler:brand-laravel
category: Development
triggers: laravel, artisan, eloquent, blade, migration, livewire, inertia, composer, php, pest, phpunit, pint, phpstan, sanctum, breeze, jetstream, middleware
markers: php, composer
recipes: laravel.about, laravel.route-list, laravel.migrate-status, laravel.migrate-pretend, laravel.migrate, laravel.test, laravel.pint-check, check.php-lint, check.phpstan, check.composer-validate, deps.composer-install, mysql.query
related: frontend-tailwind-js, sql-server-liquibase
check: *.php => check.php-lint file=$file
---

# Laravel and PHP

## Start by learning the project (cheap, read only)
1. `laravel.about`: Laravel and PHP versions, environment, drivers. Tell the user the versions; **advice depends on them** (Laravel 11 and later has a slimmer skeleton: middleware and exceptions are configured in `bootstrap/app.php`, there is no `Http/Kernel.php`; older projects differ). If unsure for the installed version, read the code that is there and follow it, or use the official docs for that version.
2. Read `composer.json` (packages: Livewire, Inertia, Sanctum, Pest vs PHPUnit) and follow what the project already uses. Look at one existing controller, model and test and copy their style.
3. `laravel.route-list` for the routes; `find_code` for where something is handled.

## Changing code
- New things start from a generator the user can run (`make:model -mfc`, `make:request`, `make:policy`); you write the files with the same content and naming.
- Validation in Form Requests; authorization in policies or gates; thin controllers, logic in actions or services; mass assignment protected (`$fillable`).
- Eloquent: eager load with `with()` to avoid N+1 queries; `chunkById`/`cursor` for large sets; define relations on both sides; casts for dates and enums; scopes for repeated conditions.
- Config values via `config()`; `env()` only inside `config/*.php`. Blade escapes with `{{ }}`; `{!! !!}` only for trusted HTML.
- Queues for slow work (mail, exports); scheduled jobs in the scheduler. Use database transactions for multi-step writes.

## Database and migrations
- Every schema change is a migration with a working `down()`. Name tables and columns like the existing ones; add indexes and foreign keys deliberately.
- Flow: write the migration, `laravel.migrate-status`, then **`laravel.migrate-pretend`** (shows the SQL, nothing runs) and show the user, and only if asked `laravel.migrate` (asks; blocked on prod). Never edit a migration that already ran elsewhere: add a new one.
- Database login for `.env`: write `DB_PASSWORD={{secret:name}}` with `write_file` (the vault handle) and Hexa puts the real value in the file after the user approves; never ask the user to paste the password into the chat. To look at data, `mysql.query` with the same handle.

## Checks (run them, report them)
After PHP edits Hexa runs `php -l` on each changed file. Then run, as far as installed: `laravel.pint-check` (style), `check.phpstan` with `target` (analysis), `laravel.test` (tests; asks). Add or update a test for new behaviour: feature tests call the route and assert the response and database state (`RefreshDatabase`, factories); unit tests for plain logic. Say plainly which of these you ran and which you could not.

## Authentication
Use the starter kit the project already has (Breeze, Jetstream, Fortify) or Sanctum for APIs; do not hand-roll password hashing or sessions. `Hash::make`, throttle login routes, `auth` middleware on protected routes, authorize with policies. Check the installed package versions before copying examples.

## Security and operations
CSRF on state-changing forms (`@csrf`); never build SQL by string concatenation; validate uploads (type, size) and store them outside `public` unless meant to be public; `APP_DEBUG=false` and a real `APP_KEY` outside local development; `php artisan config:cache` and `route:cache` in production deployments.

## Dependencies
`deps.composer-install` installs from `composer.lock` (asks). Do not run `composer update` or add packages without the user asking; say which package and why, and read its docs for the version.

Linux and shell administration Skill Administration

Linux server administration and shell scripting (Alma/Rocky/RHEL, Ubuntu/Debian, Fedora) plus Windows cmd/PowerShell basics. Use for shell commands, scripts, services, firewall, SELinux, permissions.

id bash-linux-admin · version 1.0.0 · 2.9 KB · sha256 0420459c8244… · pack (JSON)

Read the skill
---
name: bash-linux-admin
description: Linux server administration and shell scripting (Alma/Rocky/RHEL, Ubuntu/Debian, Fedora) plus Windows cmd/PowerShell basics. Use for shell commands, scripts, services, firewall, SELinux, permissions.
title: Linux and shell administration
icon: tabler:terminal-2
category: Administration
---

# Linux admin and shell

## First: know the target
Distro family changes the answer. RHEL-family (AlmaLinux, Rocky, RHEL, Fedora): `dnf`, `firewalld`, SELinux on.
Debian-family (Ubuntu, Debian): `apt`, `ufw`/`nftables`, AppArmor. If it matters and is unknown, ask or give both.

## Safety rules for commands that change things
- Show the command and say what it changes. Prefer read-only checks first (`systemctl status`, `ss -tulpn`, `df -h`).
- Use dry-run/check modes when they exist (`dnf --assumeno`, `rsync -n`, `ansible --check`).
- Back up before editing config: `cp -a file file.bak.$(date +%F)`. Validate config before reload (`nginx -t`, `sshd -t`,
  `apachectl configtest`, `visudo -c`).
- Never lock yourself out: before firewall/sshd changes, keep a second session open and don't remove the rule you are using.
- No `curl ... | bash`, no `chmod -R 777`, no `rm -rf` with an unquoted or possibly empty variable.

## Scripts
```bash
#!/usr/bin/env bash
set -euo pipefail
```
Quote every variable (`"$var"`), use `[[ ]]`, `mktemp` for temp files, `trap` for cleanup, functions for repeated
logic, `local` in functions. Check scripts with `shellcheck`. Use `getopts` or a `case` loop for options.

## Handy facts
- Services: `systemctl status|enable --now|restart <unit>`; logs `journalctl -u <unit> -n 100 --no-pager -f`.
- Timers over cron when possible (`systemctl list-timers`). Cron: check `crontab -l`, use absolute paths.
- Ports/processes: `ss -tulpn`, `lsof -i :PORT`. Disk: `df -h`, `du -xh --max-depth=1 / | sort -h`.
- Permissions: `namei -l path`, `stat`, `getfacl`. Ownership of web roots matters more than modes.
- SELinux denial suspected: `getenforce`, `ausearch -m avc -ts recent`, `restorecon -Rv <path>`,
  `semanage fcontext`, `setsebool -P`. Do not just disable SELinux; fix the label or boolean.
- Firewalld: `firewall-cmd --list-all`, `--permanent --add-service=...`, then `--reload`.

## Windows shell
PowerShell: objects, not text (`Get-ChildItem | Where-Object ... | Select-Object`), `-WhatIf`/`-Confirm` on changes,
quote paths with spaces, `$LASTEXITCODE` for native programs. cmd/batch: `%VAR%`, `if errorlevel`, `setlocal`.
Docs: learn.microsoft.com.

Monitoring and logging Skill Monitoring

Monitoring and logging: Prometheus, node_exporter, Grafana, Icinga 2 and the Elastic stack. Use for alert rules, PromQL, dashboards, check configs, log pipelines.

id monitoring-stack · version 1.0.0 · 2.7 KB · sha256 6a84ca005be6… · pack (JSON)

Read the skill
---
name: monitoring-stack
description: Monitoring and logging: Prometheus, node_exporter, Grafana, Icinga 2 and the Elastic stack. Use for alert rules, PromQL, dashboards, check configs, log pipelines.
title: Monitoring and logging
icon: tabler:chart-line
category: Monitoring
---

# Monitoring stack

Versions differ a lot (Icinga 2 vs Director, Grafana 9 vs 11, Elastic 7 vs 8). Ask the version if it matters, and check
the official docs (`devtools__web_search` topic `prometheus`, `grafana`, `icinga`, `elastic`).

## Prometheus and node_exporter
- Metric types: counter (only goes up; always wrap in `rate()`/`increase()`), gauge, histogram (use
  `histogram_quantile(0.95, sum by (le) (rate(x_bucket[5m])))`).
- Validate: `promtool check config prometheus.yml`, `promtool check rules rules.yml`, `promtool test rules`.
- Useful node_exporter metrics: `node_cpu_seconds_total` (`mode="idle"`), `node_memory_MemAvailable_bytes`,
  `node_filesystem_avail_bytes` (exclude `tmpfs`/`overlay`), `node_load1`, `node_network_receive_bytes_total`, `up`.
- CPU used %: `100 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100`.
- Alerts: use `for:` to avoid flapping, meaningful labels (`severity`), and annotations with the value and runbook link.
  Watch label cardinality (never put user IDs/URLs in labels).

## Grafana
- Dashboards as JSON/provisioning in version control; data sources provisioned in YAML. Use variables for instance/job.
- In queries use `$__rate_interval` for `rate()`. Set units and thresholds; keep panels few and readable.

## Icinga 2
- Config objects: Host, Service, CheckCommand, Notification, User, TimePeriod; use `apply Service ... for` rules and
  groups instead of repeating objects. Validate with `icinga2 daemon -C` before `systemctl reload icinga2`.
- Distributed setups use zones/endpoints and `icinga2 node wizard`; mind the certificates. Plugins live in the
  monitoring-plugins path; test a check by running the plugin by hand first, and check its exit code
  (0 OK, 1 WARNING, 2 CRITICAL, 3 UNKNOWN).

## Elastic stack
- Elasticsearch: define index templates/mappings (keyword vs text), use ILM for retention, avoid wildcard-heavy queries,
  keep shard counts sane. Kibana: KQL for quick filters, Lucene/ES|QL for more. Shippers: Elastic Agent or Beats;
  parse logs with ingest pipelines (grok/dissect). Secure with TLS and API keys; don't expose port 9200.

PowerShell and Windows admin Skill Administration

Write PowerShell scripts and do Windows administration safely: services, event logs, networking, scheduled tasks, registry, disks, users.

id powershell-windows-admin · version 1.0.0 · 4.2 KB · sha256 bd309cee0d32… · pack (JSON)

Read the skill
---
name: powershell-windows-admin
description: Write PowerShell scripts and do Windows administration safely: services, event logs, networking, scheduled tasks, registry, disks, users.
title: PowerShell and Windows admin
icon: tabler:brand-powershell
category: Administration
triggers: powershell, pwsh, ps1, windows, service, event log, scheduled task, registry, get-service, cmdlet, windows server, active directory
markers: pwsh
recipes: check.psscriptanalyzer
related: bash-linux-admin
check: *.ps1 => check.psscriptanalyzer file=$file
---

# PowerShell and Windows administration

## Investigating a machine (read only first)
Run PowerShell with `run_command` as `["pwsh","-NoProfile","-Command","<one cmdlet pipeline>"]` (use `powershell` if `pwsh` is not installed). It asks the user each time, so batch what you need into one command and **only use read cmdlets**:

| Goal | Command |
|---|---|
| a service | `Get-Service name \| Format-List Name,Status,StartType` |
| why something failed | `Get-WinEvent -FilterHashtable @{LogName='System';Level=2,3;StartTime=(Get-Date).AddHours(-6)} -MaxEvents 30 \| Format-List TimeCreated,ProviderName,Id,Message` |
| open ports and owners | `Get-NetTCPConnection -State Listen \| Select LocalPort,OwningProcess` |
| disk space | `Get-PSDrive -PSProvider FileSystem` |
| scheduled tasks | `Get-ScheduledTask \| Where State -ne Disabled` |
| installed updates | `Get-HotFix \| Sort InstalledOn -Desc \| Select -First 10` |

Say what the output shows. Do not change anything (`Set-`, `Remove-`, `Stop-`, `Restart-`, `New-`, `Disable-`, registry edits) unless the user asked for that change.

## Making a change
1. State the exact change and what it affects. Try `-WhatIf` first for cmdlets that support it (`Remove-Item x -WhatIf`).
2. Prefer reversible changes; record the old value before changing it (a registry value, a service start type).
3. Never use `-Force`, `-Recurse` on `Remove-*`, `Format-*`, `Clear-*`, or disable security features (Defender, firewall, UAC, execution policy) unless the user explicitly asked, naming it.
4. Changes to services, the registry, users, the firewall or Active Directory need the user's approval and their own confirmation that the target is the right machine.

## Writing scripts
```powershell
[CmdletBinding(SupportsShouldProcess)]
param(
    [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$Name,
    [ValidateSet('Dev','Test','Prod')][string]$Environment = 'Dev'
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
try {
    if ($PSCmdlet.ShouldProcess($Name, 'Restart service')) { Restart-Service -Name $Name }
} catch {
    Write-Error "Could not restart $Name: $($_.Exception.Message)"
    exit 1
}
```
- Approved verbs (`Get-`, `Set-`, `New-`, `Remove-`), full cmdlet names (no `gci`, `%`, `?` aliases in scripts), `Join-Path` for paths, `-LiteralPath` when names may contain `[` or `]`.
- Return **objects**, not formatted text: `Write-Output` or return values, `Format-*` only for display at the very end. Use `Write-Verbose` for progress.
- Strings: single quotes for literals, double quotes for expansion, `$($x.Prop)` inside strings. Compare with `-eq`, `-ne`, `-like`, `-match`; arrays and `$null` on the left: `$null -eq $x`.
- Never put credentials in a script: use `Get-Credential`, a SecretManagement vault, or an environment variable supplied by the caller. No `ConvertTo-SecureString -AsPlainText` with a literal.
- Remote work: `Invoke-Command -ComputerName x -ScriptBlock {...}` and `-ArgumentList`; variables from outside need `$using:name`.

## Checks
After writing a `.ps1`, `check.psscriptanalyzer` runs on it (when PSScriptAnalyzer is installed). Fix errors and warnings that point to real problems (unapproved verbs, unused variables, plain-text passwords). Then run the script with `-WhatIf` if it supports it.

Puppet Skill Infrastructure as code

Write, validate, lint and dry-run Puppet code (manifests, modules, Hiera data, roles and profiles) safely.

id puppet · version 1.0.0 · 3.4 KB · sha256 380202405b93… · pack (JSON)

Read the skill
---
name: puppet
description: Write, validate, lint and dry-run Puppet code (manifests, modules, Hiera data, roles and profiles) safely.
title: Puppet
icon: tabler:server-cog
category: Infrastructure as code
triggers: puppet, manifest, hiera, puppetfile, r10k, puppet agent, profile, epp, facter
markers: puppet, puppet-lint
recipes: puppet.parser-validate, puppet.lint, puppet.noop, puppet.apply, puppet.agent-noop, puppet.agent-run, help.puppet-describe
related: ansible, terraform
check: *.pp => puppet.parser-validate manifest=$file
---

# Puppet

Run the recipes where Puppet is installed: this PC, or `on: "ssh:<name>"` / `on: "wsl:<name>"` for a server or Linux environment. `toolchain` shows whether Puppet is installed here.

**Check or review request**: read the code, run `puppet.parser-validate` and `puppet.lint`, then answer. Do not run noop or apply for a review.

## Workflow for a change
1. **Look first.** Find the class, the profile and the role involved and the Hiera data that feeds it (`find_code`, `search_files`). Puppet code is layered: **roles** (one per machine type) include **profiles** (one per technology) which use **modules**; **Hiera data** holds values, code holds logic.
2. Edit. Keep modules small and parameters typed (`String`, `Integer`, `Optional[String]`, `Array[String]`).
3. `puppet.parser-validate` on every changed `.pp` file, then `puppet.lint`. Fix errors; fix warnings unless the repo clearly ignores them.
4. `puppet.noop` on the target (`puppet apply --noop`) or `puppet.agent-noop` on a node: shows what would change without changing it. **Read it to the user**: resources that would change, create or be removed, and notify/restart effects.
5. Only if the user asks: `puppet.apply` or `puppet.agent-run`. Always asks, only right after the matching noop on unchanged files, blocked on prod.

Example: `run_recipe {"recipe":"puppet.noop","args":{"manifest":"manifests/site.pp"},"on":"ssh:web01"}`

## Write idempotent, ordered code
- Prefer native resource types (`package`, `file`, `service`, `user`, `ini_setting`) over `exec`. An `exec` needs `creates`, `unless` or `onlyif`, else it runs every time.
- Order explicitly: `Package['nginx'] -> File['/etc/nginx/nginx.conf'] ~> Service['nginx']` (`->` order, `~>` order and notify). Dependency cycles and duplicate declarations are the common errors: read the error, it names both resources.
- Facts come as `$facts['os']['family']`, not `$::osfamily`. Look up a resource type's parameters for the installed version with `help.puppet-describe` (type name); do not invent parameters.
- Templates: EPP (`epp('module/file.epp', {...})`) over ERB for new code. Keep logic out of templates.
- `include` a class when it needs no parameters; use resource-like declarations (`class { 'x': }`) only once per class, and prefer Hiera `lookup`/automatic parameter binding.

## Secrets
Never put passwords in manifests or Hiera plain text. Use `eyaml`-encrypted values or `Sensitive[String]` and ask the user for the encrypted data.

## Report
Say: files changed, validate and lint results, the noop summary, and whether anything was applied.

Python Skill Development

Writing, testing and structuring Python (3.12 style): scripts, CLIs, small libraries, tests. Use for any Python coding task.

id python · version 1.0.0 · 2.3 KB · sha256 8601598bb1d2… · pack (JSON)

Read the skill
---
name: python
description: Writing, testing and structuring Python (3.12 style): scripts, CLIs, small libraries, tests. Use for any Python coding task.
title: Python
icon: tabler:brand-python
category: Development
---

# Python

## Defaults (unless the project shows otherwise)
- Python 3.12, type hints, `pathlib`, f-strings, `dataclasses`, `logging` (not `print`) in anything long-lived.
- Scripts: `argparse` (or `typer` if already used), a `main()` and `if __name__ == "__main__":`. Exit non-zero on failure.
- Dependencies in a venv with pinned versions (`requirements.txt` or `pyproject.toml`). Never `pip install` system-wide.
- Secrets from environment variables or a secrets manager, never in code.

## Pitfalls to avoid
- Mutable default arguments (`def f(x=[])`); bare `except:`; swallowing exceptions silently.
- `subprocess`: pass a list, not a string with `shell=True`; use `check=True`, `timeout=`, `capture_output=True, text=True`.
- Open files with `with` and an explicit `encoding="utf-8"`. Use `Path.read_text()` for small files.
- Compare floats with `math.isclose`. Use `is None`, not `== None`. Don't shadow builtins (`list`, `id`, `type`).
- `requests`/`httpx`: always set a timeout; check status; don't build SQL or shell commands from strings.
- SQL: parameterized queries only.

## Test before presenting
Use `devtools__run_code`. Write the function plus a few `assert`s covering: normal case, empty input, single item, duplicates,
boundary values, and a case that must raise. Run it. Fix failures and rerun. Show the final code and say what you ran.
Limits of `devtools__run_code`: no network, no subprocesses, no files outside its folder, 60 s max. For code that needs those,
test the pure logic and tell the user what you could not run.

## Testing real projects
`pytest` with plain asserts and fixtures; `tmp_path` for files; mock the network and the clock; one behavior per test.

## Style
Small functions, clear names, early returns, no clever one-liners. Match the surrounding code's style. Docstring on
public functions in one or two lines.

SQL Server and Liquibase Skill Databases

Write T-SQL and SQL Server DBA queries, query databases read-only, and manage schema changes with Liquibase changelogs (also Azure SQL Managed Instance).

id sql-server-liquibase · version 1.0.0 · 4.9 KB · sha256 6317c7b638cb… · pack (JSON)

Read the skill
---
name: sql-server-liquibase
description: Write T-SQL and SQL Server DBA queries, query databases read-only, and manage schema changes with Liquibase changelogs (also Azure SQL Managed Instance).
title: SQL Server and Liquibase
icon: tabler:database
category: Databases
triggers: sql, t-sql, tsql, sql server, sqlcmd, liquibase, changelog, changeset, migration, stored procedure, index, query plan, azure sql, managed instance, cdc, deadlock
markers: sqlcmd, liquibase
recipes: sql.query, sql.execute, liquibase.validate, liquibase.status, liquibase.update-sql, liquibase.update
related: azure-admin, laravel-php
---

# SQL Server and Liquibase

## Reading data from a database
Use `sql.query` (SQL Server), `mysql.query` or `psql.query`. The login is a **secret handle** from the vault, for example `{{secret:shop-test-reader}}`: put the handle in `password`, never a real password. Each query asks the user because it uses a secret.
- Ask which server, database and user; use a **read-only login**. Look at the handles listed in the prompt.
- Only `SELECT`/`WITH` is accepted. Always limit the rows (`SELECT TOP 100 ...`) and name the columns; never `SELECT *` on big tables.
- Results may contain personal data: show only what the question needs and do not copy rows into files.

Example: `run_recipe {"recipe":"sql.query","args":{"server":"sql-test.corp.local","database":"Shop","user":"reader","password":"{{secret:shop-test-reader}}","trust_server_certificate":"-C","query":"SELECT TOP 20 name, create_date FROM sys.tables ORDER BY create_date DESC"}}`

Useful read-only DBA queries: `sys.dm_exec_requests` (what runs now), `sys.dm_os_wait_stats` (what the server waits for), `sys.dm_db_index_usage_stats`, `sys.dm_exec_query_stats` with `sys.dm_exec_sql_text`, `sys.databases` (state, recovery model), `msdb.dbo.backupset` (last backups).

## Changing a database: always Liquibase
Never change a shared database with `sql.execute` unless the user explicitly asks for that one statement. Schema changes are changesets:
1. Find the master changelog and how existing changesets are written (SQL-formatted or YAML/XML) and numbered. Copy that style.
2. Add a **new** changeset; one change per changeset.
   ```sql
   --liquibase formatted sql
   --changeset derek:2026-10-add-customer-email
   ALTER TABLE dbo.Customer ADD Email nvarchar(256) NULL;
   --rollback ALTER TABLE dbo.Customer DROP COLUMN Email;
   ```
3. `liquibase.validate`, then `liquibase.status` (what is pending), then `liquibase.update-sql` (the exact SQL). **Show the user the SQL.**
4. Only if asked: `liquibase.update` (asks; right after the update-sql, blocked on prod).

Rules that prevent disasters:
- **Never edit or delete a changeset that has been applied anywhere**: its checksum is stored and Liquibase refuses to continue. Add a new changeset that fixes it.
- Every changeset has a unique `id` + `author` (+ file). Add a `--rollback` or `<rollback>` for each. Use `runOnChange:true` only for views, procedures and functions (written as `CREATE OR ALTER`).
- Preconditions (`--preconditions onFail:MARK_RAN`) when the object might exist already. Use contexts or labels for data that belongs only to one environment.
- Connection details live in the `liquibase.properties` the user keeps; do not write passwords into it or into the changelog.

## T-SQL habits
- Schema-qualify objects (`dbo.Customer`); `SET NOCOUNT ON;` at the top of procedures; `TRY/CATCH` with `THROW`; parameters, never string-concatenated SQL (`sp_executesql` with parameters if dynamic SQL is unavoidable).
- Set-based code over cursors and loops; `EXISTS` over `COUNT(*) > 0`; avoid functions on indexed columns in `WHERE` (not sargable); explicit column lists in `INSERT`.
- Indexes: look at the actual plan and the missing-index DMVs as hints, not orders; an index helps reads and costs writes.
- Use `datetime2` and `nvarchar` for new columns; always `ORDER BY` when order matters; mind implicit conversions (a varchar parameter against an nvarchar column).
- Destructive statements (`DROP`, `TRUNCATE`, `DELETE` without `WHERE`) need the user's explicit confirmation and a backup or rollback plan.

## Azure SQL Managed Instance notes
Connection is over the instance's private endpoint or public endpoint on port 3342; permissions are server logins and roles as in SQL Server; some instance-level features differ from on-premises. For CDC and mirroring: the capture jobs need SQL Agent, and schema changes on captured tables must be coordinated (add columns to the capture instance deliberately). Say when you are unsure and point to the official documentation instead of guessing.

Terraform and OpenTofu Skill Infrastructure as code

Write, check, plan and change Terraform or OpenTofu infrastructure code (HCL), including Azure (azurerm) resources, modules, state and providers.

id terraform · version 1.0.0 · 4.7 KB · sha256 41913c69d703… · pack (JSON)

Read the skill
---
name: terraform
description: Write, check, plan and change Terraform or OpenTofu infrastructure code (HCL), including Azure (azurerm) resources, modules, state and providers.
title: Terraform and OpenTofu
icon: tabler:brand-terraform
category: Infrastructure as code
triggers: terraform, tofu, opentofu, hcl, tfvars, tfstate, azurerm, provider, module, plan, apply
markers: terraform, tofu, tflint
recipes: terraform.init, terraform.fmt-check, terraform.fmt, terraform.validate, terraform.tflint, terraform.plan, terraform.apply, terraform.state-list, terraform.state-show, help.terraform, help.terraform-schema
related: azure-admin
check: *.tf => terraform.fmt-check dir=$dir
---

# Terraform

Use recipes, not run_command. Terraform is `terraform.*`; on a Windows PC without it, `toolchain` shows how to install it.

**Check or review request** ("check the code", "what is wrong"): read the files, run `terraform.fmt-check` and `terraform.validate` (and `terraform.tflint` if installed), then answer with what they report plus what you saw in the code. Do not run init, plan or apply for a review. If a tool is not installed, say so and carry on with the others.

## Workflow for a change
1. **Look first.** `list_dir` / `find_code` for where it belongs. Read `versions.tf` (or the `terraform {}` block) and `.terraform.lock.hcl` for the Terraform and provider versions. Follow the existing file layout and naming.
2. `terraform.init` once per folder (needs your cloud login for the backend).
3. Edit with `edit_file`. Keep the change small; one concern per change.
4. `terraform.fmt-check`, then `terraform.validate`, then `terraform.tflint` when installed. Fix every error before going on.
5. `terraform.plan`. **Read the summary to the user in plain words**: adds, changes, destroys. Call out every line with `destroy`, `must be replaced` or `forces replacement` and say which resource and why.
6. Only if the user asks to apply: `terraform.apply`. It asks the user, works only right after an unchanged plan, and is blocked on prod workspaces.

Never: edit state or `*.tfstate` by hand, run destroy, put secrets in `.tf` or `.tfvars` files, change the backend without being asked.

## Do not guess arguments
Resource arguments change between provider versions. Look them up for the installed version:
- `help.terraform-schema` saves the full schema; then `read_output` with `grep` on the resource name, for example `azurerm_mssql_managed_instance`.
- `help.terraform` with `command` for CLI options.

Example: `run_recipe {"recipe":"terraform.plan","args":{"dir":"infra/prod-network"}}`

## Style that avoids trouble
- Pin versions: `required_version` and `required_providers` with `~>`; commit `.terraform.lock.hcl`.
- `for_each` (a map or set of stable keys) instead of `count` for things with identity, so removing one item does not renumber and recreate the others. Use `moved {}` blocks to rename or move resources without recreating them.
- Variables get a `type` and `description`; secret ones get `sensitive = true`. Pass secrets with environment variables (`TF_VAR_name`) or a Key Vault data source, never in files.
- Modules: `main.tf`, `variables.tf`, `outputs.tf`, `versions.tf`. A module takes inputs and returns outputs; it does not read global state.
- `lifecycle { prevent_destroy = true }` on databases and other data stores; `ignore_changes` only with a comment saying why.
- Prefer `depends_on` rarely; reference attributes so Terraform sees the dependency.

## Azure (azurerm) notes
- The provider needs `features {}`. From provider 4.x a `subscription_id` is required in the provider block or `ARM_SUBSCRIPTION_ID`. Check the version in the lock file before advising.
- Authenticate with the Azure CLI login (`az.account-show` shows who and which subscription). Check the subscription before any plan.
- Names are global for storage accounts, key vaults and web apps; add a suffix. Tag resources the way the existing code does.
- Many resources recreate when a "ForceNew" argument changes (location, name, SKU family): the plan shows `forces replacement`; stop and ask before accepting it for stateful resources.

## OpenTofu
Same language and commands. The recipes call `terraform`; if only `tofu` is installed say so and tell the user it needs the `terraform` name or a shim.

## Report
End with: what changed, the plan summary, what you verified (validate/plan results) and anything you could not check.

Web: Laravel and Node.js Skill Development

Web development: Laravel (PHP), Node.js/TypeScript backends, and HTML/CSS/JavaScript frontends, including web-app and API security basics. Use for web app code.

id web-laravel-node · version 1.0.0 · 2.5 KB · sha256 7af9b213bf89… · pack (JSON)

Read the skill
---
name: web-laravel-node
description: Web development: Laravel (PHP), Node.js/TypeScript backends, and HTML/CSS/JavaScript frontends, including web-app and API security basics. Use for web app code.
title: Web: Laravel and Node.js
icon: tabler:brand-nodejs
category: Development
---

# Web development

Check the project's versions first (`composer.json`, `package.json`, lockfiles) and follow the existing structure.
Verify APIs in the docs (`devtools__web_search` topic `laravel`, `nodejs`, `typescript`, `web`) instead of guessing.

## Laravel
- Use artisan generators (`make:model -mfc`, `make:request`, `make:policy`). Migrations for every schema change.
- Validation in Form Requests; authorization via policies/gates; mass assignment guarded with `$fillable`.
- Avoid N+1 queries: eager load with `with()`; use `chunk`/`cursor` for big sets; add indexes for lookups.
- Config via `.env` + `config()` (never `env()` outside config files); `php artisan config:cache` in production.
- Queues for slow work; scheduled tasks via `schedule:run`. Tests with Pest/PHPUnit: feature tests hit routes, use factories.
- Blade escapes by default (`{{ }}`); only use `{!! !!}` for trusted HTML.

## Node.js / TypeScript
- Use current LTS. Decide ESM vs CJS and stay consistent. `strict` mode in `tsconfig.json`; avoid `any`.
- `async/await` with try/catch at boundaries; never leave promises unhandled; set timeouts on outbound calls.
- Validate all input (zod or similar). Use environment variables for config; commit the lockfile; `npm ci` in CI.
- Test pure logic with `devtools__run_code` (node) where possible; real projects use vitest/jest.

## Frontend
- Semantic HTML, labels on inputs, keyboard focus, sufficient contrast. CSS: flexbox/grid, `rem`, custom properties,
  mobile-first media queries. JS: `const`/`let`, no globals, `fetch` with error handling, avoid `innerHTML` with user data.

## Security checklist (always)
Parameterized queries, escape output, CSRF protection on state-changing forms, strict CORS, rate limit auth routes,
hash passwords (bcrypt/argon2), don't log secrets, HTTPS only, set security headers, validate file uploads.

Compose services Tool (recipe) Containers

Show the services of the Docker Compose project in the folder and their state (docker compose ps --all).

id docker-compose-ps · version 1.0.0 · 0.6 KB · sha256 d69c97c4b99b… · pack (JSON)

Read the tool definition
{
  "command": [
    "docker",
    "compose",
    "ps",
    "--all"
  ],
  "risk": "inspect",
  "description": "Show the services of the Docker Compose project in the folder and their state (docker compose ps --all).",
  "args": [
    {
      "name": "dir",
      "description": "Folder to run in, relative to the workspace",
      "required": false,
      "pattern": "",
      "flags": "",
      "secret": false,
      "multiline": false,
      "default": "",
      "kind": "path",
      "values": [],
      "allowDash": false
    }
  ],
  "environment": "",
  "secretEnv": {},
  "secretUse": "",
  "hostArg": "",
  "timeout": 60,
  "creds": false,
  "parser": "plain",
  "requires": null,
  "okCodes": [
    0
  ],
  "envArg": "",
  "needs": "",
  "guard": ""
}

Helm releases Tool (recipe) Containers

List the Helm releases of all namespaces with their status and chart version (helm list --all-namespaces).

id helm-list · version 1.0.0 · 0.6 KB · sha256 1c7cb8565359… · pack (JSON)

Read the tool definition
{
  "command": [
    "helm",
    "list",
    "--all-namespaces"
  ],
  "risk": "inspect",
  "description": "List the Helm releases of all namespaces with their status and chart version (helm list --all-namespaces).",
  "args": [
    {
      "name": "dir",
      "description": "Folder to run in, relative to the workspace",
      "required": false,
      "pattern": "",
      "flags": "",
      "secret": false,
      "multiline": false,
      "default": "",
      "kind": "path",
      "values": [],
      "allowDash": false
    }
  ],
  "environment": "",
  "secretEnv": {},
  "secretUse": "",
  "hostArg": "",
  "timeout": 60,
  "creds": true,
  "parser": "plain",
  "requires": null,
  "okCodes": [
    0
  ],
  "envArg": "",
  "needs": "",
  "guard": ""
}

Pod resource use Tool (recipe) Containers

Show CPU and memory use of the pods in a namespace (kubectl top pods). Needs the metrics server in the cluster.

id kubectl-top-pods · version 1.0.0 · 0.8 KB · sha256 673af89401f8… · pack (JSON)

Read the tool definition
{
  "command": [
    "kubectl",
    "top",
    "pods",
    "?-n",
    "?{{namespace}}"
  ],
  "risk": "inspect",
  "description": "Show CPU and memory use of the pods in a namespace (kubectl top pods). Needs the metrics server in the cluster.",
  "args": [
    {
      "name": "namespace",
      "description": "Namespace (default: the current one)",
      "required": false,
      "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$",
      "flags": "",
      "secret": false,
      "multiline": false,
      "default": "",
      "kind": "text",
      "values": [],
      "allowDash": false
    },
    {
      "name": "dir",
      "description": "Folder to run in, relative to the workspace",
      "required": false,
      "pattern": "",
      "flags": "",
      "secret": false,
      "multiline": false,
      "default": "",
      "kind": "path",
      "values": [],
      "allowDash": false
    }
  ],
  "environment": "",
  "secretEnv": {},
  "secretUse": "",
  "hostArg": "",
  "timeout": 60,
  "creds": true,
  "parser": "plain",
  "requires": null,
  "okCodes": [
    0
  ],
  "envArg": "",
  "needs": "",
  "guard": ""
}

Query JSON with jq Tool (recipe) Code and data

Run a jq filter over a JSON file and print the result, for example ".items[].metadata.name".

id jq-query · version 1.0.0 · 0.8 KB · sha256 1fe8ab294019… · pack (JSON)

Read the tool definition
{
  "command": [
    "jq",
    "--color-output",
    "--monochrome-output",
    "{{filter}}",
    "{{file}}"
  ],
  "risk": "inspect",
  "description": "Run a jq filter over a JSON file and print the result, for example \".items[].metadata.name\".",
  "args": [
    {
      "name": "filter",
      "description": "jq filter, for example .items[] | .name",
      "required": true,
      "pattern": "",
      "flags": "",
      "secret": false,
      "multiline": false,
      "default": "",
      "kind": "text",
      "values": [],
      "allowDash": true
    },
    {
      "name": "file",
      "description": "JSON file",
      "required": true,
      "pattern": "",
      "flags": "",
      "secret": false,
      "multiline": false,
      "default": "",
      "kind": "path",
      "values": [],
      "allowDash": false
    },
    {
      "name": "dir",
      "description": "Folder to run in, relative to the workspace",
      "required": false,
      "pattern": "",
      "flags": "",
      "secret": false,
      "multiline": false,
      "default": "",
      "kind": "path",
      "values": [],
      "allowDash": false
    }
  ],
  "environment": "",
  "secretEnv": {},
  "secretUse": "",
  "hostArg": "",
  "timeout": 30,
  "creds": false,
  "parser": "plain",
  "requires": null,
  "okCodes": [
    0
  ],
  "envArg": "",
  "needs": "",
  "guard": ""
}

Query YAML with yq Tool (recipe) Code and data

Evaluate a yq expression over a YAML file and print the result, for example ".spec.template.spec.containers[].image".

id yq-eval · version 1.0.0 · 0.8 KB · sha256 72b27866a3fb… · pack (JSON)

Read the tool definition
{
  "command": [
    "yq",
    "eval",
    "{{expression}}",
    "{{file}}"
  ],
  "risk": "inspect",
  "description": "Evaluate a yq expression over a YAML file and print the result, for example \".spec.template.spec.containers[].image\".",
  "args": [
    {
      "name": "expression",
      "description": "yq expression",
      "required": true,
      "pattern": "",
      "flags": "",
      "secret": false,
      "multiline": false,
      "default": "",
      "kind": "text",
      "values": [],
      "allowDash": true
    },
    {
      "name": "file",
      "description": "YAML file",
      "required": true,
      "pattern": "",
      "flags": "",
      "secret": false,
      "multiline": false,
      "default": "",
      "kind": "path",
      "values": [],
      "allowDash": false
    },
    {
      "name": "dir",
      "description": "Folder to run in, relative to the workspace",
      "required": false,
      "pattern": "",
      "flags": "",
      "secret": false,
      "multiline": false,
      "default": "",
      "kind": "path",
      "values": [],
      "allowDash": false
    }
  ],
  "environment": "",
  "secretEnv": {},
  "secretUse": "",
  "hostArg": "",
  "timeout": 30,
  "creds": false,
  "parser": "plain",
  "requires": null,
  "okCodes": [
    0
  ],
  "envArg": "",
  "needs": "",
  "guard": ""
}

Search with ripgrep Tool (recipe) Code and data

Search the files of the workspace for a regular expression with ripgrep (rg), showing file, line and text; at most 40 matches per file.

id rg-search · version 1.0.0 · 1.0 KB · sha256 92b974ed8bdd… · pack (JSON)

Read the tool definition
{
  "command": [
    "rg",
    "--line-number",
    "--no-heading",
    "--color",
    "never",
    "--max-count",
    "40",
    "-e",
    "{{pattern}}",
    "?--",
    "?{{path}}"
  ],
  "risk": "inspect",
  "description": "Search the files of the workspace for a regular expression with ripgrep (rg), showing file, line and text; at most 40 matches per file.",
  "args": [
    {
      "name": "pattern",
      "description": "Regular expression to find",
      "required": true,
      "pattern": "",
      "flags": "",
      "secret": false,
      "multiline": false,
      "default": "",
      "kind": "text",
      "values": [],
      "allowDash": true
    },
    {
      "name": "path",
      "description": "File or folder to search (default: the whole folder)",
      "required": false,
      "pattern": "",
      "flags": "",
      "secret": false,
      "multiline": false,
      "default": "",
      "kind": "path",
      "values": [],
      "allowDash": false
    },
    {
      "name": "dir",
      "description": "Folder to run in, relative to the workspace",
      "required": false,
      "pattern": "",
      "flags": "",
      "secret": false,
      "multiline": false,
      "default": "",
      "kind": "path",
      "values": [],
      "allowDash": false
    }
  ],
  "environment": "",
  "secretEnv": {},
  "secretUse": "",
  "hostArg": "",
  "timeout": 60,
  "creds": false,
  "parser": "plain",
  "requires": null,
  "okCodes": [
    0
  ],
  "envArg": "",
  "needs": "",
  "guard": ""
}