Course navigation
Claude SkillsLesson 13 of 15

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 evaluates shell commands and injects the results before Claude 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.

DataExpressionType
Today's date$CURRENT_DATEBuilt-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

  1. You type a slash command (e.g. /standup)
  2. Claude Code reads SKILL.md
  3. Shell commands in ## Context run; output is injected
  4. Claude sees live data plus your Steps instructions
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

Compare the same skill with and without dynamic context to see the difference.

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.

/standup — live output

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

Claude Code
$ /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
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.
Context injected before skill execution
// 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);

Code Review — feature/auth-refresh

[Critical]

jwt.verify does not validate expiry. Pass ignoreExpiration: false explicitly.

[Warning]

process.env.SECRET is not type-guarded. Add a startup check.

Large diffs can exceed Claude's context window. For big changes, limit 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.
Claude Code
$ /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
[OK] Branch is not main — safe to proceed
[OK] No uncommitted changes
[OK] Last commit looks complete: fix: handle token expiry edge case
[WARN] 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)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 — prefer --name-only over a full diff when you only need file names.
  • Never inject secrets directly — avoid $(cat .env). Reference env values by name inside Steps instead.
  • Label each line clearly — e.g. Branch: $(git branch …) so Claude knows which value is which.
  • Test with a dry run first — run on a throwaway branch to confirm injected values look correct.
Start with $CURRENT_DATE and $(git branch --show-current). Add the staged diff only when the skill genuinely needs to read code.

Before you continue

  • Add a ## Context block with $CURRENT_DATE or shell substitutions for live data.
  • Shell substitution runs in Claude Code only — not in claude.ai chat skills.
  • Label context lines clearly and keep injected output small.
  • Never inject secrets via shell commands that read .env files.
  • Next lesson: Skills with Subagents.

What's Next

Dynamic context injects live data at runtime. Next: skills with sub-agents for multi-step, parallel workflows.