environments
Skill8 starsChanged 12 days agoMITView on GitHub
Use before any action against a non-local environment (deploy, SSH, migration, remote logs or data, test accounts, test data), when asked what version runs where, and when the user says "deploy lên staging", "ssh vào server", "chạy trên prod", "account test", "môi trường nào", "thêm môi trường", "thêm server".
- Reads credentials
We split this skill into the rules it gives an agent
36 rules. 0 are common, 19 are distinctive, and 17 are very specific to this project.
0
Common
Most of the 4 edited versions we read keep these.
19
Distinctive
This author's own choices. Worth a look.
17
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Very specific: line 15
Read .agents/environments.json at the repo root, in full, before the first environment action of the session.
- Distinctive: line 17
Do not improvise hosts or commands in the meantime.
- Distinctive: line 18
When the user states a new fact (server, account, URL, rule), put it in the registry instead of keeping it in chat.
- Distinctive: line 19
Every registry change is shown as a diff and written only after a yes.
- Very specific: line 27
Use the environment the user named, otherwise defaultEnvironment.
- Very specific: line 28
Never reach a confirm-each-step environment by default or inference.
- Distinctive: line 29
If a request could mean prod ("live", "the real site", "customers see this"), ask which environment.
- Distinctive: line 51
When a rule is stricter, follow it.
- Distinctive: line 52
When a rule depends on something you cannot observe (a customer event, telling the team), ask the user before acting.
- Distinctive: line 58
Before showing remote logs or query results in chat, mask secrets, tokens, and personal data such as emails and phone numbers.
- Distinctive: line 71
Before the first step:
- Distinctive: line 87
Run only that step, show the relevant output, then run its check.
- Very specific: line 89
Do not run the next step and do not invent a fix.
- Very specific: line 91
Never merge steps to save confirmations: no && across steps, no ad-hoc scripts, no interactive SSH session.
- Distinctive: line 93
After every write step, ok or failed, append one line to the deploy log (section 5).
- Very specific: line 95
After the last step: run every verify.
- Distinctive: line 99
Use the registry's commands exactly as written, substituting only placeholders.
- Distinctive: line 110
When a README, runbook, or old environment note disagrees with the registry or the repo's deploy script, follow the registry, then the …
- Very specific: line 111
Read the section of references/deploy-targets.md for each service type you touch.
- Distinctive: line 115
When asked what runs where ("môi trường nào đang chạy bản nào", "prod đang ở commit nào"), or before planning a promotion:
- Very specific: line 139
When testing.scope and data.testDataAllowed disagree, follow the stricter one.
- Distinctive: line 143
If you cannot confirm that, do not trigger the flow.
- Very specific: line 159
Before the deploy plan, present this checklist filled in with evidence.
- Very specific: line 169
Never an UPDATE or DELETE without a WHERE.
- Distinctive: line 172
If the change cannot be reversed and restoring the backup is the only way back, the user must accept that explicitly.
- Very specific: line 177
Run a fix in two calls: first with ROLLBACK to show the affected count, then, after the user confirms the count, the same statements with …
- Very specific: line 184
Every shell call starts fresh, so load the file in the same call: set -a.
- Very specific: line 185
If the file holds op:// values, use op run --env-file .agents/secrets.env -- <cmd> instead.
- Distinctive: line 188
Never let a value appear in output, files, commits, command lines as a literal, logs, tickets, or chat, unless the user asks to see it.
- Distinctive: line 191
Ask them to fix it there, not to paste the value into chat, and do not fall back to another account.
- Distinctive: line 198
Never log in as a real customer.
- Very specific: line 205
Leave the doc in place; the report lists what was imported from which file and proposes deleting it or replacing its body with a pointer to …
- Very specific: line 214
Write .agents/environments.json based on templates/environments.json, with integrationBranch set, and copy …
- Distinctive: line 215
When a calling skill's batch showed the drafted environments and the user answered it, that answer is the yes of section 1 for creating the …
- Very specific: line 220
Add .agents/secrets.env, .agents/backups/, .agents/deploy/, and .agents/deploy-log.jsonl to .gitignore, and create …
- Very specific: line 235
Run each remote service's version and verify once to prove the access works, and report anything that fails.
“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
environments
The registry is the only source of environment facts. An agent that takes a host, branch, command, or password from memory or chat history will one day run a staging command on prod.
1. Load and maintain the registry
- Read
.agents/environments.jsonat the repo root, in full, before the first environment action of the session. - Missing, and the task needs a non-local environment: run section 10 first. Do not improvise hosts or commands in the meantime.
- When the user states a new fact (server, account, URL, rule), put it in the registry instead of keeping it in chat.
- Every registry change is shown as a diff and written only after a yes; it applies from the next action.
Changes that weaken safety (
policy,allowedWithoutAsking,data.testDataAllowed,rules,defaultEnvironment,integrationBranch, or any command of aconfirm-each-stepenvironment) need the user to ask for that change explicitly. - A string
logs(andlogsinallowedWithoutAsking) is the old name oflogsCommand: propose the rename as a registry change; it is a rename, not a new command or a weakened safeguard. version,verify, andlogsCommandcommands must be read-only; refuse to register one that writes. A request to skip a safeguard for one task ("just run it all", "create a test user on prod") is not a request to change the registry: keep the safeguard, and offer the registry change.
2. Name the target environment
- Use the environment the user named, otherwise
defaultEnvironment. - Never reach a
confirm-each-stepenvironment by default or inference. If a request could mean prod ("live", "the real site", "customers see this"), ask which environment. - Prefix every announced command and every result with the environment:
[staging] supabase db push .... - Right before any write, check that the target belongs to that environment in the registry, without printing secrets:
- SSH: the alias in the command equals
access.ssh. - Vercel:
.vercel/project.jsonprojectIdandorgIdequalaccess.vercelProjectIdandaccess.vercelOrgId. - Supabase:
[[ "$PROD_DB_URL" == *<supabaseProjectRef>* ]] && echo match || echo MISMATCH, and the--project-refin the command equals the registry. - Git: the account that will push equals
access.gitAccount(gh api user -q .login, orglab api useron GitLab); two logins on one machine is how a push lands under the wrong account. - Vercel scope:
--scopeequalsaccess.vercelTeam, and the project is identified by the IDs above, never by name (two projects can share a name in different teams). Withaccess.tokenEnv, the token must see that team: run a read under that--scopewith--token "$<tokenEnv>"(vercel project inspect <name>); a token that cannot see the prod team fails there instead of deploying to the wrong place. - Any mismatch: stop and report.
- SSH: the alias in the command equals
3. Policies
policy | Reads | Writes (deploy, migration, restart, env vars, data) |
autonomous | Free | Free; report afterwards |
confirm-writes | Free | Show the whole plan, get one confirmation, run it; stop and ask on any unexpected result |
confirm-each-step | Ask first, except registry commands listed in allowedWithoutAsking (empty by default) | Section 4, every step |
allowedWithoutAskinglists registry commands by name (version,logsCommand,verify), pluslogsQueryfor bounded Better Stack reads perbetterstack-logssection 4; any other remote command, including ad-hoc SQL, asks first. Local reads (git, files in the repo,op whoami) are always free.rulesadd to the policy. When a rule is stricter, follow it; when it is looser than the policy, follow the policy and point out the conflict. When a rule depends on something you cannot observe (a customer event, telling the team), ask the user before acting.data.testDataAllowed: falseis a kill switch: never create, modify, or delete records in that environment, except through reviewed migrations shipped by the deploy protocol. Where test data is allowed, puttestDataMarkeron every record you create and delete those records when done.- A service with
trigger: gitdeploys on a push or merge into its environment'sbranch; that git write is a deploy and follows this table, whateverdeploylists. Onconfirm-each-stepit is a plan step, and merging a PR into that branch needs the same confirmation (main deploying prod is the usual case). - Approval never carries over: not from an earlier session, an earlier deploy, or another environment.
- Before showing remote logs or query results in chat, mask secrets, tokens, and personal data such as emails and phone numbers.
- A service's
logsobject names its Better Stack source; reading an environment's logs followsbetterstack-logssection 4, under this environment's policy.
4. confirm-each-step protocol (prod)
Placeholders in registry commands:
<sha>: the full 40-character SHA being deployed.<previous-sha>: the code version captured in pre-flight fromversion; rollback depends on it. For a database,versionreturns the latest applied migration instead; capture it too.<timestamp>: UTCYYYYMMDD-HHMM.- Anything else (
<migration-name>, ...): filled in the plan where the user can see it.
Before the first step:
- Pre-flight, read-only: capture every service's
version, resolve<sha>, list pending migrations, check every rule (deploy windows, events), and create the clean deploy checkout (git worktree add .agents/deploy/<sha> <sha>); commands that read the local tree run from there. - Database or data changes in the deploy: complete the section 8 checklist first.
- Prove what was tested is what ships: the tree at
<sha>must equal the tree that passed on staging (git diff --stat <staging-sha> <sha>is empty). Proof that staging passed is an E2E evidence file or the user's explicit word. - Present a numbered plan: services in
deployOrder(default db before web), then each service'sdeployitems in order, one item per step. For every step, show the exact command (secrets masked), what it changes, its check, and its undo. Where the registry has no per-step check or undo, propose one and mark it "proposed"; the plan approval covers it. A step may be skipped only when the plan says why (e.g. no function changed). - Get approval of the plan. Approving the plan does not approve any step.
For each step:
- Show the exact command and ask "Run step N?"; run nothing until the answer is yes.
- Run only that step, show the relevant output, then run its check.
- Non-zero exit, unexpected output, or a failed check: stop.
Do not run the next step and do not invent a fix.
Report what state each service is in now (e.g. migrations applied but web still on
<previous-sha>), present the options (retry, undo, roll back, investigate), and wait. - Never merge steps to save confirmations: no
&&across steps, no ad-hoc scripts, no interactive SSH session.
After every write step, ok or failed, append one line to the deploy log (section 5).
After the last step: run every verify; code services' version must print <sha>, and the database's must equal the newest migration at <sha>. Report what ran, the running versions, the check results, and the rollback commands with placeholders filled in.
5. Deploy and access servers
- Use the registry's commands exactly as written, substituting only placeholders.
- A remote service needs
version,deploy,verify, androllback(the schema requires them outsideautonomousenvironments) and atrigger(git,cli,manual);logsCommandwhere the platform has a CLI for it. One is missing: propose it fromreferences/deploy-targets.md, get it confirmed, write it into the registry, then use it. - SSH only through the alias in
access.ssh(defined in~/.ssh/config), one remote command per call:ssh <alias> '<cmd>'. - Docker Compose on a server (shared hosts above all): follow the
server-touchskill. - "Pushed" is not "deployed": a deploy is done when
versionmatches the target andverifypasses. Fortrigger: gitit is the reverse trap: the push already deployed, so check what the branch would trigger before pushing it. - Deploy log: after every write against a non-local environment (deploy step, migration, rollback), append one JSON line to
.agents/deploy-log.jsonlin the main checkout (gitignored, append-only, so parallel agents never conflict):{"ts":"<UTC ISO>","env":"prod","service":"web","action":"deploy","sha":"<sha>","previousSha":"<previous-sha>","by":"<git user.email>","result":"ok|failed","verify":"ok|failed|skipped","rollback":"<filled rollback command>"}. One>>per line; no secrets, no command output. A failed step is logged too; the log records what was attempted,versionstays the truth about what runs. - When a README, runbook, or old environment note disagrees with the registry or the repo's deploy script, follow the registry, then the script; say what conflicts and propose fixing the doc.
- Read the section of
references/deploy-targets.mdfor each service type you touch; it holds the platform traps (Supabase link state, Vercel git vs. CLI deploys, VPS release folders).
6. Version status across environments
When asked what runs where ("môi trường nào đang chạy bản nào", "prod đang ở commit nào"), or before planning a promotion:
git fetch origin --prune, then run every service'sversion, environment by environment. On aconfirm-each-stepenvironment this asks first unlessversionis inallowedWithoutAsking.- Report one table: environment, service, short SHA, commit subject and date (
git log -1 --format='%h %s (%cr)' <sha>), and how far behind the integration branch it is (git rev-list --count <sha>..origin/<int>). - For each promotion path, list what would ship:
git log --oneline <prod-sha>..<staging-sha>. - Flag problems instead of smoothing them over:
- A remote environment that is behind:
git rev-list --count <sha>..origin/<int>above 0 on staging, or prod behind staging, is a warning line, not just a number. unknownor an error: the service has no working version endpoint (references/version-endpoint.md).- A SHA that no remote branch contains (
git branch -r --contains <sha>is empty): someone deployed unpushed code. - Services of one environment on different SHAs, when they deploy together.
- A remote environment that is behind:
7. Testing per environment
testing.scope says what tests may run there:
scope | Allowed |
full | Any test, including destructive ones, data resets, and load tests |
non-destructive | Functional and E2E tests on records you create (with testDataMarker) and delete afterwards; no data resets, load or stress tests, bulk imports, or changes to other people's records |
smoke-only | Read-only flows with the listed accounts: open pages, search, view; no submit that creates or changes data, no payment, no message to a real person |
none | No tests |
- Missing
testing:smoke-onlyon aconfirm-each-stepenvironment,non-destructiveelsewhere. Whentesting.scopeanddata.testDataAlloweddisagree, follow the stricter one. testing.rulesadd project specifics (sandbox keys, QA hours, which flows make up the smoke test).- On
smoke-only, list the flows you will run and get a yes before opening the browser; a failure is reported, never fixed or retried by changing data on that environment. - External side effects cause most testing harm: trigger payments only with test-mode keys, emails or SMS only to addresses the team owns, webhooks only to sandboxes. If you cannot confirm that, do not trigger the flow; ask.
- Changing shared settings (feature flags, admin config) counts as a data change: record the old value first and restore it when done.
- Evidence follows the
e2e-verifyskill.
8. Database and data changes
Applies to every migration, backfill, data fix, import, bulk admin action, or manual SQL against a confirm-writes or confirm-each-step environment.
Classify every statement first:
| Class | Examples | Extra gate |
| Additive | CREATE TABLE, nullable ADD COLUMN, CREATE INDEX CONCURRENTLY | The checklist |
| Data-changing | UPDATE, DELETE, backfill INSERT, data fix scripts | Row counts and a copy of the affected rows |
| Destructive or locking | DROP, RENAME, ALTER ... TYPE, SET NOT NULL, new FK or unique constraint on a large table, TRUNCATE | An expand/contract plan and a separate yes per statement |
Before the deploy plan, present this checklist filled in with evidence.
On confirm-each-step, any line answered "no" or "unknown" stops the deploy until the user resolves it; on confirm-writes, it is raised in the plan.
- Backup: method (point-in-time recovery or schema + data dumps), when it was taken, and proof it is usable (PITR restore point after the last change, or both dump files present and non-empty). A fresh backup is the first step of the deploy, not a claim about last night.
- Migration approach: backward-compatible with the code running now and the code being deployed (expand now, contract in a later release), and the deploy order between database and code.
- Tested on staging: the same migration files ran and passed there (
git diff --stat <staging-sha> <sha> -- supabase/migrationsis empty), ideally on a realistic data volume. - Dry run: the list of migrations about to apply equals the expected list; no surprise migration.
- Data changes: per data-changing statement, its WHERE clause, the expected row count, and where the affected rows are copied first (backup table or export).
Measure counts without changing anything:
BEGIN; <statement>; <count check>; ROLLBACK;orSELECT count(*)with the same WHERE, each asked first on prod. Never anUPDATEorDELETEwithout a WHERE. - Locks and duration: tables touched, their row counts, and which statements rewrite or lock them; large tables need batching,
CONCURRENTLY, or a maintenance window. - Rollback: the reverse migration is written and reviewed before deploying. If the change cannot be reversed and restoring the backup is the only way back, the user must accept that explicitly.
- Side effects: triggers, RLS policies, cron jobs, realtime subscriptions, and functions or webhooks that fire on changed rows (an
UPDATEthat sends customer emails). - Timing and people: inside the allowed window, and who has been told (ask the user).
Manual data fixes belong in a reviewed migration or script in the repo, not typed into a SQL console.
Run a fix in two calls: first with ROLLBACK to show the affected count, then, after the user confirms the count, the same statements with COMMIT.
9. Secrets and test accounts
- The registry is committed and holds no secret values; the schema rejects literals in fields named like password, token, secret, key, DB URL, or connection string.
- A secret is a reference:
{"secret": "env:NAME"}: from the shell environment or the gitignored.agents/secrets.env; commands use it as"$NAME". Every shell call starts fresh, so load the file in the same call:set -a; . .agents/secrets.env; set +a; <cmd>. If the file holdsop://values, useop run --env-file .agents/secrets.env -- <cmd>instead. Loading secrets this way does not count as changing a registry command.{"secret": "op://vault/item/field"}: 1Password, read on demand without printing, assigned and exported in the same shell call:NAME="$(op read 'op://...')"; export NAME; <cmd>.
- Never let a value appear in output, files, commits, command lines as a literal, logs, tickets, or chat, unless the user asks to see it.
- Browser logins: prefer a saved session (Playwright storage state) per account; when a password must be typed, it goes only into the login field, never into a reply.
- A reference does not resolve: tell the user which reference and why (
op whoamifails = not signed in; item not found = missing entry; env var empty = missing line in.agents/secrets.env). Ask them to fix it there, not to paste the value into chat, and do not fall back to another account. - A secret pasted into chat is exposed: do not repeat it, write it anywhere, or use it in a command.
Say it must be rotated, and ask the user to put the new value in
.agents/secrets.env(or anop://reference) themselves. .agents/secrets.envis mode 600 and gitignored:[ "$(stat -f %Lp .agents/secrets.env 2>/dev/null || stat -c %a .agents/secrets.env)" = 600 ]andgit check-ignore -q .agents/secrets.env; a wider mode or a tracked file is reported, andchmod 600is the fix.- Scope:
.agents/secrets.envand the registry hold only what the agent needs to work: deploy and CLI tokens, MCP and API keys for tooling, database URLs for migrations, test account passwords. The app's own runtime keys (Stripe, Brevo, OpenAI, ...) live in the project's env files or the platform's env store, never here; an agent that finds one insecrets.envor the registry moves it out and reports it. - Pick accounts by
rolefrom the target environment only. Never log in as a real customer; on prod use only the accounts listed there.
10. Create the registry
- Draft from repo evidence first: existing environment docs (
.claude/environments*.md,docs/**/environments*.md, environment notes inAGENTS.md,CLAUDE.mdor README),.env*.example(variable names only),.vercel/project.json,vercel.json,supabase/config.toml,Dockerfile, compose files,ecosystem.config.*, CI workflows, deploy scripts. An existing environment doc is a source to import, not a question: take its environments, URLs, branches, SSH aliases, policies or rules, and account roles and logins into the draft. A secret value in it is never copied: it becomes anenv:reference, and moving and rotating it is waiting on the user. Leave the doc in place; the report lists what was imported from which file and proposes deleting it or replacing its body with a pointer to.agents/environments.json, so the two cannot drift. 1b. Inventory the app's variables per environment: scan.env*.example,package.jsondependencies (Stripe, Brevo, Sentry, ...), andsupabase/functions/(Deno.env.get) for the services the code calls and the variable names it reads. Compare those names with what each environment defines, read-only and names only (vercel env ls <environment>,supabase secrets list --project-ref <ref>, the project's env files; a remote read follows the environment's policy), and record where they live asappEnvSource. Report one table, a row per variable and a column per environment, each cell set or missing, never a value. A missing name is reported under waiting on the user; a payment or email service that runs on a live key outside prod is a finding. - Ask the user only what the repo cannot tell, in one batch, your drafts shown; it always starts with these, unless the registry already records them or a calling skill asked them in this run (
project-initsection 2, or theharness-mapsetup batch in its section 3, whose answers are taken as given):- Which branch PRs/MRs go into (
integrationBranch,worktree-flowsection 0), never assumed. - Which environments exist: local or dev, staging, prod, and any other, each with its URL and the branch it deploys from. Then SSH aliases, test account roles and logins, rules such as deploy windows.
- Which branch PRs/MRs go into (
- Write
.agents/environments.jsonbased ontemplates/environments.json, withintegrationBranchset, and copytemplates/environments.schema.jsonnext to it. When a calling skill's batch showed the drafted environments and the user answered it, that answer is the yes of section 1 for creating the registry; only later changes need their own diff and yes. An environment the user does not know yet is left out and reported, never invented;environmentsmay stay empty while onlyintegrationBranchis known. A standard one the user says the project does not have (dev, staging or prod) goes inabsentEnvironments, soharness-mapstops asking for it. - Defaults: local and dev
autonomouswith testingfull; stagingconfirm-writeswith testingnon-destructive; prodconfirm-each-stepwithallowedWithoutAsking: [],testDataAllowed: false, and testingsmoke-only. Writing a looser prod setting needs the user's explicit words. Add
.agents/secrets.env,.agents/backups/,.agents/deploy/, and.agents/deploy-log.jsonlto.gitignore, and create.agents/secrets.env.examplelisting everyenv:name with an empty value. Then create or top up the real.agents/secrets.envin the main checkout from it, empty values only; an existing file is never overwritten, only missing names are appended:m="$(dirname "$(git rev-parse --path-format=absolute --git-common-dir)")"; mkdir -p "$m/.agents"; (umask 077; touch "$m/.agents/secrets.env") [ -n "$(tail -c1 "$m/.agents/secrets.env")" ] && echo >> "$m/.agents/secrets.env" # a last line without a newline stays intact awk -F= 'FILENAME==ARGV[1]{k=$1; sub(/^export /,"",k); have[k]=1; next} /^[A-Z][A-Z0-9_]*=/ && !($1 in have){print $1"="}' \ "$m/.agents/secrets.env" .agents/secrets.env.example >> "$m/.agents/secrets.env"In a worktree, link it as
worktree-flowsays (ln -s "$m/.agents/secrets.env" .agents/secrets.env). Tell the user which names to fill, and that they fill them in that file themselves, with the value or anop://reference; never ask for a value in chat.harness-mapshows each name that is still empty or absent as missing on its environment's card.- Validate:
npx -y ajv-cli@5.0.0 validate --spec=draft2020 -s .agents/environments.schema.json -d .agents/environments.json. - A service without a version endpoint gets one per
references/version-endpoint.md, shipped as a normal PR/MR. - Run each remote service's
versionandverifyonce to prove the access works, and report anything that fails. On prod, run them only after a yes: the calling skill's batch answer (the Environments row ofharness-mapsection 3) when there is one, else ask; a no leaves the command under waiting on the user.
Other versions4 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 4
- robium-ai/robium★ 93same name
- rubixkube-io/rubixkube-for-ai★ 1same name
- syntropic137/harness-app-template★ 0same name
- syntropic137/software-leverage-points★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository27 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- releaseSkill
- ask-or-decideSkill
- axiSkill
- betterstack-logsSkill
- bug-triageSkill
- chrome-devtools-axiSkill
- e2e-verifySkill
- feature-buildSkill
- feature-statusSkill
- fe-guardrailsSkill
- flow-traceSkill
- fresh-reviewSkill
- gnhfSkill
- harness-mapSkill
- jira-bug-hunterSkill
- knowledge-placementSkill
- logging-standardSkill
- project-initSkill
- root-causeSkill
- security-passSkill
- server-touchSkill
- stowSkill
- verify-loopSkill
- visionSkill
- worktree-flowSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

