Last reviewed: 2026-06-08
Writing coding agent tutorials with realistic, runnable examples is straightforward until you need to show how the agent calls an API or reads a token. At that point, many tutorial authors either hard-code a placeholder that breaks on copy-paste or, worse, leak a real credential into a public repo. This guide explains a stable set of patterns for keeping secrets out of the example layer while keeping the examples genuinely useful.
Direct answer
The core principle is simple: every secret your tutorial example needs must come from the environment at runtime, never from the file the reader copies. In practice this means three things:
Instruction files stay credential-free. Files like AGENTS.md, CLAUDE.md, .cursorrules, or Copilot custom instructions tell the agent how to behave. They must not contain tokens, keys, or environment-specific paths. They can reference an environment variable by name — for example OPENAI_API_KEY — but the value must never appear in the file itself.
Workflow YAML uses ${{ secrets.SECRET_NAME }} syntax only. In GitHub Actions, all credentials flow through the encrypted secrets store and are injected via the secrets context. The tutorial YAML you publish shows the reference, not the value. Readers register their own secret under the same name in their repository’s settings before running the workflow.
Model-gateway base URLs and API keys are environment variables, not inline strings. When your tutorial shows an agent calling a model gateway, the base URL and the key are always read from the process environment. This is true whether the agent is Codex CLI, Claude Code, Cursor Agent, or a custom script that calls a gateway endpoint.
Following these three patterns makes your tutorial examples safe to commit to a public repository, safe to fork, and safe to run in CI without modification.
For broader release checks, see AI Coding Agent Setup, Security, and Model Routing .
Who this is for
This guide is written for:
- Tutorial and documentation authors who write coding agent walkthroughs and need examples that are both shareable and runnable.
- Engineering team leads who maintain internal runbooks and want agents to be able to follow them without the runbooks embedding production credentials.
- Developers setting up their first coding agent CI pipeline who want a reference for where secrets go and where they do not.
If you are looking for a broader treatment of how to set permission boundaries across your whole agent setup, see Set Safe Permission and Secret Boundaries for Coding Agents.
Key takeaways
- Instruction files (AGENTS.md, CLAUDE.md, .github/copilot-instructions.md) are version-controlled and often public. Never put secrets in them.
- GitHub Actions encrypted secrets are the correct channel for passing credentials to agent workflows. The ${{ secrets.NAME }} syntax injects the value at runtime without printing it in logs.
- Environment variable references in tutorial code (process.env.COMET_API_KEY, os.environ[“COMET_API_KEY”]) are the reader-friendly way to show where a key goes without exposing a value.
- Claude Code memory files (.claude/memory.md or project-level CLAUDE.md) persist context across sessions — they must contain guidance about which env vars to use, not the values.
- OpenAI Codex reads AGENTS.md for repository-level instructions. The same credential-free rule applies.
- A well-formed secret-free tutorial example should pass a basic secret-scan check (git secrets, trufflehog, or similar) with no findings.
Instruction files: what goes in, what stays out
AGENTS.md (OpenAI Codex)
The AGENTS.md file at the repository root or in subdirectories gives Codex behavioural rules, scope limits, test commands, and approved API patterns. According to the OpenAI Codex AGENTS.md reference, the file is read automatically when the agent starts a task in that directory tree.
Safe to include:
- Environment variable names the agent should read (COMET_API_KEY, GITHUB_TOKEN)
- The base URL pattern to use, expressed as an env var reference ($COMET_BASE_URL)
- Instructions to never log or print credential values
- Scope limits on which files and directories the agent may modify
Not safe to include:
- Any actual key, token, password, or bearer credential
- Hard-coded internal hostnames or IP addresses that would break in other environments
- Paths that only exist on your machine
A minimal safe example block:
markdown
API access
All model calls use the gateway at $COMET_BASE_URL. Authenticate with $COMET_API_KEY. Do not log, print, or commit these values.
CLAUDE.md and Claude Code memory files
Claude Code supports project-level instruction files and persistent memory files. The Claude Code memory documentation describes how these files are loaded and when they persist across sessions.
The same credential-free rule applies. A CLAUDE.md at your repository root is frequently committed to version control. A memory file may persist on a developer’s machine, but if the tutorial instructs readers to create one, the contents will end up in many environments.
Safe pattern for a CLAUDE.md gateway reference:
markdown
Model gateway
Use the endpoint documented in the current gateway config. Read the base URL from COMET_BASE_URL and the key from COMET_API_KEY. Verify current endpoint paths and model IDs against the gateway documentation before making calls.
GitHub Copilot custom instructions
The .github/copilot-instructions.md file provides repository-level custom instructions to Copilot. This file is committed to the repository. The same rule applies: reference env var names, never values.
GitHub Actions workflow YAML: the right secrets pattern
When your tutorial includes a workflow YAML file, all credentials must flow through GitHub Actions encrypted secrets. Readers create the secret under Settings > Secrets and variables > Actions in their own repository before running the workflow.
The tutorial YAML shows only the reference:
jobs:
agent-task:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run coding agent task
env:
COMET_API_KEY: ${{ secrets.COMET_API_KEY }}
COMET_BASE_URL: ${{ secrets.COMET_BASE_URL }}
run: |
# agent invocation goes here
Key points from the GitHub Actions workflow syntax reference:
- Secrets injected via env: at the step level are available to the process as environment variables.
- GitHub automatically redacts known secret values from log output, but this is a safety net, not a substitute for proper secret handling.
- The GITHUB_TOKEN secret is provisioned automatically; you do not need to create it manually.
- Do not use echo or run: env to print all environment variables in tutorial steps — this produces noisy output and may expose values if the automatic redaction misses an edge case.
What the reader must do before running your workflow
Every tutorial that uses secrets should include a short setup prerequisite block:
Before running this workflow:
- Go to your repository Settings > Secrets and variables > Actions.
- Create a secret named COMET_API_KEY with your gateway key.
- Create a secret named COMET_BASE_URL with your gateway base URL.
- Commit and push. The workflow reads these at runtime.
This keeps the tutorial honest: the reader knows exactly what they need to supply.
Model gateway calls: env-var-first patterns
When your tutorial example shows the agent making a model call through a gateway — such as CometAPI — the call setup must read credentials from the environment, not from an inline string.
Python example:
import os
import httpx
base_url = os.environ[“COMET_BASE_URL”] # verify current endpoint path in gateway docs api_key = os.environ[“COMET_API_KEY”]
Exact endpoint paths, request fields, and model IDs should be verified
against the current gateway documentation before use.
response = httpx.post( f"{base_url}/api/text/chat", headers={“Authorization”: f"Bearer {api_key}"}, json={ “model”: “”, “messages”: [{“role”: “user”, “content”: “Hello”}] } ) response.raise_for_status()
Shell example:
curl -s \
-H "Authorization: Bearer $COMET_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "<verify-model-id>", "messages": [{"role": "user", "content": "Hello"}]}' \
"$COMET_BASE_URL/api/text/chat"
In both cases, COMET_BASE_URL and COMET_API_KEY are set in the shell session or injected by the CI workflow. The tutorial shows the structure; the reader supplies the values.
If you want readers to try the examples against CometAPI, direct them to Start with CometAPI to obtain their own API key, then set it as described above.
Smoke-test workflow
After writing a tutorial example, run this quick check before publishing:
Setup assumptions
- A fresh clone of the tutorial repository (no local env vars set yet)
- A secret-scanning tool available (git secrets or trufflehog)
Happy-path request plan
- Run git secrets –scan (or equivalent) against the full repository tree.
- Grep for common secret patterns: grep -rn ‘sk-’, grep -rn ‘Bearer [A-Za-z0-9]’ — expect zero results in committed files.
- Export env vars from your own environment and run the example script locally. Confirm it completes without an authentication error.
- Check that AGENTS.md, CLAUDE.md, and any .github/copilot-instructions.md files contain no literal key or token values.
Error-path check
- Unset COMET_API_KEY and run the script again. Confirm it fails with a clear error (missing environment variable or authentication rejected) rather than silently using an empty string or a hard-coded fallback.
Minimum assertions
- Zero secret-scan findings in committed files.
- Script exits with a non-zero code when the required env var is absent.
- Workflow YAML contains only ${{ secrets.NAME }} references, never inline values.
What the smoke test must not assert
- Do not assert specific model IDs, response latency, or pricing — these can change and are not part of secret hygiene.
- Do not assert that a specific gateway endpoint path is stable — verify that separately against current gateway documentation.
Sample log record (fill in after each check run):
smoke_test_run_id: date: YYYY-MM-DD repository: secret_scan_tool: scan_findings: 0 env_var_missing_exit_code: workflow_yaml_checked: true notes:
Failure modes
- Evidence gap: the agent cannot inspect the failing log, source page, pull request, or local command output. The safe action is to stop and record the missing evidence instead of guessing.
- Scope drift: the agent edits files that are not connected to the observed failure. Keep the repair tied to the failing signal and leave unrelated cleanup for a separate task.
- Environment mismatch: the local check uses different versions, credentials, feature flags, or runtime settings than the hosted path. Record the mismatch before treating the result as proof.
- Unreviewed fallback: the agent changes models, endpoints, permissions, or retry behavior to make a run pass without preserving the review boundary. Treat access and provider failures as operational blockers, not topic failures.
- Weak handoff: the final note says the issue is fixed but omits the command, result, changed files, and remaining uncertainty. That makes the next operator repeat the investigation.
Sources checked
GitHub Actions encrypted secrets documentation - accessed 2026-06-08; purpose: verify secret-handling boundaries for workflow runs.
GitHub Actions workflow syntax documentation - accessed 2026-06-08; purpose: verify workflow permission configuration areas.
OpenAI Codex AGENTS.md guidance - accessed 2026-06-08; purpose: verify repository instruction-file context for coding agents.
Claude Code memory documentation - accessed 2026-06-08; purpose: verify project memory and instruction-file context for agent workflows.
GitHub Copilot custom repository instructions - accessed 2026-06-08; purpose: verify .github/copilot-instructions.md scope and loading for repository-level agent guidance.
CometAPI chat completions endpoint documentation - accessed 2026-06-08; purpose: verify current endpoint path structure for model gateway examples; exact request fields and model IDs must be confirmed against live docs.
CometAPI model overview - accessed 2026-06-08; purpose: gateway model availability context; model IDs must be verified against current docs before use.
Contract details to verify
| Area | What to verify | Source URL | Accessed | Safe candidate wording |
|---|---|---|---|---|
| GitHub Actions secret injection | That ${{ secrets.NAME }} syntax is still the current recommended pattern for step-level env injection | https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions | 2026-06-08 | Use ${{ secrets.SECRET_NAME }} to inject credentials at the step level |
| AGENTS.md file loading | That AGENTS.md is still automatically read at the repository root and subdirectory level by Codex CLI | https://github.com/openai/codex/blob/main/docs/agents_md.md | 2026-06-08 | AGENTS.md at the repository root is read automatically when Codex starts a task; verify current file-discovery rules in the linked docs |
| CLAUDE.md and memory file scope | Which memory files Claude Code loads by default and which persist across sessions | https://code.claude.com/docs/en/memory | 2026-06-08 | Claude Code loads project-level instruction files and optional memory files; verify current persistence rules in the linked docs |
| CometAPI chat endpoint path | That /api/text/chat is the current canonical path for chat completions calls | https://apidoc.cometapi.com/api/text/chat | 2026-06-08 | Verify the exact endpoint path in current CometAPI documentation before using it in agent scripts |
| Copilot instructions file path | That .github/copilot-instructions.md is still the supported path for repository-level Copilot instructions | https://docs.github.com/en/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-repository-instructions | 2026-06-08 | Use .github/copilot-instructions.md for repository-level Copilot guidance; verify current path in linked docs |
Reader next step
Compare the workflow against Start with CometAPI .
Use AI Coding Agent Setup, Security, and Model Routing as the next comparison point. Keep Triage CI Failures With a Coding Agent Without Losing the Evidence nearby for setup and permission checks.
FAQ
Can I use a placeholder like YOUR_API_KEY_HERE instead of an env var reference?
A placeholder is acceptable in a README prose explanation but not in executable code or workflow YAML. In any file that gets run, use os.environ[“COMET_API_KEY”] or $COMET_API_KEY so the reader’s tooling immediately shows a clear error if the variable is not set, rather than sending a literal placeholder string to the API.
What if my tutorial needs to show what a real API response looks like?
Record a sanitised response once against your own test environment, strip any account-specific fields, and embed that as a static fixture in your tutorial. Do not call the live API at tutorial-build time or commit a response that contains account identifiers.
Should AGENTS.md be in .gitignore?
No. AGENTS.md is an instruction file that agents read from the repository. It should be committed. The rule is that it must not contain secret values — not that it must be hidden.
My agent needs a different base URL in CI versus local development. How do I handle that?
Define a single environment variable name (COMET_BASE_URL) and set it to different values in each environment: in GitHub Actions through the encrypted secrets store; locally through your shell profile or a .env file that is listed in .gitignore. The tutorial code and the AGENTS.md reference only the variable name, never a hard-coded URL.
What is the risk of accidentally committing a real key?
Once a secret is in git history it is considered compromised even if you delete it in a later commit. Rotate the key immediately, audit what it was used for, and use a secret-scan pre-commit hook going forward to prevent recurrence.
Does this apply to short-lived tokens too?
Yes. Even a token that expires in an hour is a security risk if it appears in a public repository. Rotation cycles do not change the requirement to keep credential values out of committed files.