$CURRENT_DATE$(git branch)git diff --cachedshell substitutionauto-populated context

Dynamic Context in Skills

Skills are static SKILL.md files — but they can pull live data at invocation time. Add a ## Context block and Claude Code will evaluate shell commands and inject the results before Claude even reads your instructions.

What is dynamic context?

When Claude Code runs a skill, it processes the SKILL.md file before sending anything to Claude. If you include a ## Context section with shell substitution expressions, Claude Code evaluates them and injects the real output into the prompt.

This means your skills can automatically know:

📅
Today's date
$CURRENT_DATE
Built-in variable
🌿
Git branch
$(git branch --show-current)
Shell substitution
📂
Staged files
$(git diff --cached --name-only)
Shell substitution
🔍
Full staged diff
$(git diff --cached)
Shell substitution
📝
Last commit
$(git log -1 --pretty='%h %s')
Shell substitution
🔧
Env variable
$(echo $NODE_ENV)
Shell substitution

How it works

You type /standup
Claude Code reads SKILL.md
Shell commands run, output injected
Claude sees live data + your Steps
ℹ️ Info: Shell substitution only works in Claude Code (the desktop CLI). In claude.ai chat skills, the Context section is treated as plain text — Claude reads it literally, not evaluated.

Before and after — /standup

The simplest way to see the value of dynamic context is to compare the same skill with and without it.

❌ Without dynamic context
SKILL.md
---
name: standup
description: Write my daily standup update.
---

## Steps
1. Ask the user what they worked on yesterday and today.
2. Format as three bullet points: Yesterday / Today / Blockers.
Claude has no idea what branch you are on or what changed. It will ask you — or guess.
✅ With dynamic context
SKILL.md
---
name: standup
description: Write my daily standup update.
---

## Context
- Today's date: $CURRENT_DATE
- Current git branch: $(git branch --show-current)
- Staged files: $(git diff --cached --name-only)

## Steps
1. Use the branch name to infer the feature being worked on.
2. Use the staged file list to determine what changed.
3. Format as three bullet points: Yesterday / Today / Blockers.
4. Populate "Today" automatically from the staged files.
Claude already knows today's date, the branch, and which files changed. The standup writes itself.

/standup — live output

Below is what the terminal looks like when you run /standup with dynamic context enabled.

$ /standup
◆ Injecting context...
$CURRENT_DATE → 2026-05-07
git branch → feature/auth-refresh
git diff --cached → src/auth.ts, src/tokens.ts
◆ Running skill: standup
Daily Standup — 2026-05-07
Branch: feature/auth-refresh
• Yesterday Worked on JWT token validation logic
• Today Completing auth refresh flow (auth.ts, tokens.ts)
• Blockers None
✔ Done
💡 Tip: Notice that Claude populated "Yesterday" and "Today" from the branch name and staged files — you did not type anything. That is dynamic context in action.

Example — /review with staged diff

Injecting the full staged diff means Claude reviews exactly the code you are about to commit — not the whole file, not a pasted snippet.

SKILL.md
---
name: review
description: Review the code I am about to commit.
---

## Context
- Current date: $CURRENT_DATE
- Branch: $(git branch --show-current)
- Staged diff:
$(git diff --cached)

## Steps
1. Read the staged diff from context.
2. Look for logic errors, missing error handling, and security issues.
3. Output findings grouped as Critical, Warnings, and Suggestions.

## Constraints
- Only review the staged changes, not the whole file.
- Do not suggest stylistic rewrites unless they affect correctness.
claude.ai/claude-code · /review running
// Context injected before skill execution
Current date: 2026-05-07
Branch: feature/auth-refresh
Staged diff (truncated):
+ export async function refreshToken(token: string) {
+ const decoded = jwt.verify(token, process.env.SECRET);
- return jwt.sign(decoded, process.env.SECRET);
+ return jwt.sign({ ...decoded, iat: Date.now() }, process.env.SECRET);
+ }
Code Review — feature/auth-refresh
🔴 Critical
jwt.verify does not validate expiry. Pass { ignoreExpiration: false } explicitly or the token may be accepted after expiry.
🟡 Warning
process.env.SECRET is not type-guarded. Add a startup check and throw if undefined.
⚠️ Note: Large diffs (thousands of lines) will exceed Claude's context window. For big changes, consider limiting the injected diff with git diff --cached -- src/auth.ts to a single file.

Example — /deploy-check with multiple sources

A pre-deployment checklist skill can pull the branch, last commit, and working-tree status all in one go.

SKILL.md
---
name: deploy-check
description: Run a pre-deployment checklist before I deploy.
---

## Context
- Date: $CURRENT_DATE
- Branch: $(git branch --show-current)
- Last commit: $(git log -1 --pretty=format:"%h %s")
- Uncommitted changes: $(git status --short)

## Steps
1. Confirm the branch is not "main" or "master" unless the user says it is intentional.
2. Flag any uncommitted changes as a blocker.
3. Show the last commit hash and message.
4. Ask the user to confirm they have run tests.
$ /deploy-check
◆ Injecting context...
Date → 2026-05-07
Branch → feature/auth-refresh
Last commit → a3f2c1b fix: handle token expiry edge case
Uncommitted → (none)
Pre-Deployment Checklist
✔ Branch is not main — safe to proceed
✔ No uncommitted changes
✔ Last commit looks complete: fix: handle token expiry edge case
⚠ Have you run the test suite? (confirm before deploying)

Dynamic context syntax reference

ExpressionWhat it injectsWorks in
$CURRENT_DATEToday's date (YYYY-MM-DD)Claude Code
$(git branch --show-current)Active branch nameClaude Code
$(git diff --cached --name-only)List of staged file pathsClaude Code
$(git diff --cached)Full staged diff (use carefully with large changes)Claude Code
$(git log -1 --pretty='%h %s')Hash + message of last commitClaude Code
$(git status --short)Uncommitted changes (porcelain format)Claude Code
$(echo $NODE_ENV)Any environment variable valueClaude Code
$(cat package.json | head -5)First 5 lines of any fileClaude Code

Best practices

📏
Keep injected output small
Long diffs or file dumps push Claude toward its context limit. Prefer --name-only over a full diff when you only need file names.
🔒
Never inject secrets directly
Avoid $(cat .env). If Claude logs the conversation, secrets appear in plain text. Access env values by name inside Steps instead.
🏷️
Label each line clearly
Use a short label before each expression (e.g. "Branch: $(git branch …)") so Claude can parse which value is which without guessing.
🧪
Test with a dry run first
Run the skill once with an empty diff or on a throwaway branch to confirm the injected values look correct before relying on them in production.
💡 Tip: Start with $CURRENT_DATE and $(git branch --show-current). They are low-risk, always relevant, and immediately make your skills feel much smarter. Add the staged diff only when the skill genuinely needs to read code.

What's Next

Dynamic context unlocks real-time data. Next: combine skills with sub-agents to orchestrate multi-step, parallel workflows.