Compare commits

..

7 Commits

Author SHA1 Message Date
Claude
93effadd31 refactor: Use SessionStart teleport matcher instead of separate hooks
Change approach from separate PreTeleport/PostTeleport hook events to
using SessionStart with a `teleport` matcher. This is cleaner since
teleporting to CLI starts a new session anyway.

SessionStart matchers:
- `*` - All session starts
- `teleport` - Only teleported sessions (web → CLI)
- `fresh` - Only fresh sessions (not teleported)

Removes pre-teleport.sh example since there's no pre-teleport hook.
2025-12-15 21:43:32 +00:00
Claude
fee53699c3 feat: Add PreTeleport and PostTeleport hook events
Add documentation and examples for new teleport hooks that allow users
to automate workflows when sessions transfer between web and CLI:

- PreTeleport: Runs before teleporting (stash work, sync state)
- PostTeleport: Runs after teleporting (pull changes, start dev servers)

This addresses the common workflow where users teleport from web to CLI
and need to run setup commands like `yarn dev:staging`.

Slack thread: https://anthropic.slack.com/archives/C096H3HP75G/p1765833639134099?thread_ts=1765833353.488839&cid=C096H3HP75G
2025-12-15 21:25:55 +00:00
GitHub Actions
eb87245010 chore: Update CHANGELOG.md 2025-12-13 00:59:55 +00:00
GitHub Actions
3680637065 chore: Update CHANGELOG.md 2025-12-12 23:31:50 +00:00
GitHub Actions
2192c86c20 chore: Update CHANGELOG.md 2025-12-12 01:29:45 +00:00
kashyap murali
dfd3494132 Merge pull request #13739 from anthropics/claude/slack-session-01GzKi42xM3SphuxeQ4De88U
Remove footer from code-review plugin output
2025-12-11 14:42:30 -08:00
Claude
e8cca9a7af Remove footer from code-review plugin output
Remove the "Generated with Claude Code" footer and feedback CTA
from the code review comment template as it adds noise without
providing value after the first viewing.
2025-12-11 22:40:32 +00:00
6 changed files with 196 additions and 232 deletions

View File

@@ -1,221 +0,0 @@
# ANT_ONLY_METADATA_USER_ID Implementation Specification
## Overview
This document specifies the implementation of the `ANT_ONLY_METADATA_USER_ID` environment variable feature for Claude Code. This feature allows internal Anthropic jobs (like Claude Oracle, Oncall, Ambient, etc.) to pass custom metadata through Claude Code sessions to the Anthropic API for tracking, rate limiting, and incident triage purposes.
## Background
From the Slack discussion:
- Internal API jobs launched via Claude Code currently lack user metadata showing `job_id` or `username` in `api_usage`
- ~85% of requests from heavy CC users (like Closing The Loop org) have no user_metadata or job identifier
- This metadata is critical for:
- Managing Internal API rate limits
- Triaging incidents
- Setting up alerting that pings the DRI researchers
- Understanding which jobs are driving token usage
## Requirements
1. **Environment Variable**: Claude Code must read an environment variable called `ANT_ONLY_METADATA_USER_ID`
2. **API Integration**: The value must be passed to all Anthropic Messages API calls in the `metadata.user_id` field
3. **Tree Shaking**: Only Anthropic internal builds should be able to use this feature
4. **Format**: The expected format is a JSON object: `{"user": "<anthropic_username>", "job": "<job_name>"}`
- Example: `{"user": "tedm", "job": "tedm-1208-mu-g-18x"}`
- Or: `{"user": "vinke", "job": "claude-oracle:fluorine:vinke"}`
## Implementation
### 1. Environment Variable Reading
In the appropriate configuration/env module (likely `src/config/env.ts` or similar):
```typescript
// Environment variable for Anthropic internal builds only
// This is used to pass job metadata to the API for usage tracking
export function getAntOnlyMetadataUserId(): string | undefined {
// Only available in Anthropic internal builds
if (!isAnthropicBuild()) {
return undefined;
}
return process.env.ANT_ONLY_METADATA_USER_ID;
}
```
### 2. API Request Metadata
When constructing API requests to the Anthropic Messages API, add the metadata:
```typescript
// In the API client module (e.g., src/api/anthropic.ts)
import { getAntOnlyMetadataUserId } from '../config/env';
function buildApiRequestMetadata(): Record<string, string> | undefined {
const metadataUserId = getAntOnlyMetadataUserId();
if (!metadataUserId) {
return undefined;
}
return {
user_id: metadataUserId
};
}
// When creating a message:
const response = await client.messages.create({
model: selectedModel,
max_tokens: maxTokens,
messages: conversationMessages,
// ... other parameters
metadata: buildApiRequestMetadata()
});
```
### 3. Tree Shaking for Internal Builds
The feature should be conditionally compiled out for public builds using build-time flags:
```typescript
// Using a build-time constant
declare const __ANT_INTERNAL_BUILD__: boolean;
export function isAnthropicBuild(): boolean {
// This will be replaced at build time
// For internal builds: true
// For public builds: false (and the code will be tree-shaken)
if (typeof __ANT_INTERNAL_BUILD__ !== 'undefined') {
return __ANT_INTERNAL_BUILD__;
}
return false;
}
```
In the build configuration (esbuild/webpack/rollup):
```javascript
// For public builds:
define: {
'__ANT_INTERNAL_BUILD__': 'false'
}
// For internal builds:
define: {
'__ANT_INTERNAL_BUILD__': 'true'
}
```
### 4. Validation (Optional but Recommended)
```typescript
function validateMetadataUserId(value: string): boolean {
try {
const parsed = JSON.parse(value);
return typeof parsed.user === 'string' && typeof parsed.job === 'string';
} catch {
// Also allow simple string format for backward compatibility
return typeof value === 'string' && value.length > 0;
}
}
export function getValidatedAntOnlyMetadataUserId(): string | undefined {
const value = getAntOnlyMetadataUserId();
if (value && !validateMetadataUserId(value)) {
console.warn('ANT_ONLY_METADATA_USER_ID has invalid format. Expected JSON: {"user": "...", "job": "..."}');
return undefined;
}
return value;
}
```
## Usage by Internal Services
Services like Claude Oracle should set this environment variable before launching Claude Code sessions:
```python
# In Claude Oracle / coo job code
import os
import json
# Set the metadata before spawning Claude Code
os.environ['ANT_ONLY_METADATA_USER_ID'] = json.dumps({
"user": username, # Anthropic username
"job": job_name # e.g., "claude-oracle:fluorine:vinke"
})
# Then launch Claude Code session...
```
Or via command line:
```bash
ANT_ONLY_METADATA_USER_ID='{"user":"tedm","job":"tedm-1208-mu-g-18x"}' claude --headless ...
```
## Data Flow
```
┌─────────────────────────────────────────────────────────────────┐
│ COO Job / Oracle / Oncall / etc. │
│ Sets: ANT_ONLY_METADATA_USER_ID='{"user":"..","job":".."}' │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Claude Code CLI │
│ Reads: process.env.ANT_ONLY_METADATA_USER_ID │
│ Adds to API calls: metadata: { user_id: "..." } │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Anthropic API │
│ Receives: metadata.user_id in request │
│ Stores in: api_usage.metadata_user_id (BigQuery) │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ BigQuery: anthropic.api_production.api_usage │
│ Fields populated: │
│ - metadata_user_id │
│ - device_id (if included) │
│ - claude_code_session_id (if included) │
└─────────────────────────────────────────────────────────────────┘
```
## Testing
1. **Unit Tests**:
- Test that `getAntOnlyMetadataUserId()` returns undefined when env var is not set
- Test that it returns the value when set (in internal builds)
- Test validation of JSON format
2. **Integration Tests**:
- Verify metadata is included in API requests
- Verify tree-shaking removes the code in public builds
3. **E2E Validation** (after deployment):
- Run a Claude Code session with the env var set
- Query BigQuery `anthropic.api_production.api_usage` to verify `metadata_user_id` is populated
## Security Considerations
1. **Internal Only**: The tree-shaking ensures this feature is not available in public builds
2. **No Secrets**: The metadata should not contain sensitive information
3. **Validation**: Input validation prevents injection attacks
## Related Files to Modify (Internal Repo)
Based on patterns in the bundled CLI, likely files to modify:
1. `src/config/env.ts` or similar - Add env var reading
2. `src/api/anthropic.ts` or similar - Add metadata to API requests
3. `build.config.ts` or similar - Add build-time flag for internal builds
4. Tests for the above
## References
- Slack thread: Internal API metadata discussion
- BigQuery tables: `anthropic.api_production.api_usage`, `api_events`
- Anthropic API docs: [Messages API metadata parameter](https://docs.anthropic.com/en/api/messages)

View File

@@ -1,5 +1,32 @@
# Changelog
## 2.0.69
- Minor bugfixes
## 2.0.68
- Fixed IME (Input Method Editor) support for languages like Chinese, Japanese, and Korean by correctly positioning the composition window at the cursor
- Fixed a bug where disallowed MCP tools were visible to the model
- Fixed an issue where steering messages could be lost while a subagent is working
- Fixed Option+Arrow word navigation treating entire CJK (Chinese, Japanese, Korean) text sequences as a single word instead of navigating by word boundaries
- Improved plan mode exit UX: show simplified yes/no dialog when exiting with empty or missing plan instead of throwing an error
- Add support for enterprise managed settings. Contact your Anthropic account team to enable this feature.
## 2.0.67
- Thinking mode is now enabled by default for Opus 4.5
- Thinking mode configuration has moved to /config
- Added search functionality to `/permissions` command with `/` keyboard shortcut for filtering rules by tool name
- Show reason why autoupdater is disabled in `/doctor`
- Fixed false "Another process is currently updating Claude" error when running `claude update` while another instance is already on the latest version
- Fixed MCP servers from `.mcp.json` being stuck in pending state when running in non-interactive mode (`-p` flag or piped input)
- Fixed scroll position resetting after deleting a permission rule in `/permissions`
- Fixed word deletion (opt+delete) and word navigation (opt+arrow) not working correctly with non-Latin text such as Cyrillic, Greek, Arabic, Hebrew, Thai, and Chinese
- Fixed `claude install --force` not bypassing stale lock files
- Fixed consecutive @~/ file references in CLAUDE.md being incorrectly parsed due to markdown strikethrough interference
- Windows: Fixed plugin MCP servers failing due to colons in log directory paths
## 2.0.65
- Added ability to switch models while writing a prompt using alt+p (linux, windows), option+p (macos).

View File

@@ -93,11 +93,6 @@ Found 3 issues:
<link to file and line with full sha1 + line range for context>
🤖 Generated with [Claude Code](https://claude.ai/code)
<sub>- If this code review was useful, please react with 👍. Otherwise, react with 👎.</sub>
---
- Or, if you found no issues:
@@ -108,8 +103,6 @@ Found 3 issues:
No issues found. Checked for bugs and CLAUDE.md compliance.
🤖 Generated with [Claude Code](https://claude.ai/code)
---
- When linking to code, follow the following format precisely, otherwise the Markdown preview won't render correctly: https://github.com/anthropics/claude-code/blob/c21d3c10bc8e898b7ac1a2d745bdc9bc4e423afe/package.json#L10-L15

View File

@@ -1,6 +1,6 @@
---
name: Hook Development
description: This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.
description: This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", "teleport hook", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.
version: 0.1.0
---
@@ -239,7 +239,12 @@ Execute when user submits a prompt. Use to add context, validate, or block promp
Execute when Claude Code session begins. Use to load context and set environment.
**Example:**
**Matchers for SessionStart:**
- `*` - All session starts
- `teleport` - Only when session started via teleport (web → CLI)
- `fresh` - Only for fresh sessions (not teleported)
**Example (general context loading):**
```json
{
"SessionStart": [
@@ -256,12 +261,58 @@ Execute when Claude Code session begins. Use to load context and set environment
}
```
**Example (teleport-specific setup):**
```json
{
"SessionStart": [
{
"matcher": "teleport",
"hooks": [
{
"type": "command",
"command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/post-teleport.sh"
}
]
}
]
}
```
**Example script (post-teleport.sh):**
```bash
#!/bin/bash
cd "$CLAUDE_PROJECT_DIR" || exit 0
# Pull latest changes from the teleported branch
if [ -d ".git" ]; then
echo "🔄 Pulling latest changes..."
git pull origin "$(git branch --show-current)" 2>/dev/null || true
fi
# Install dependencies if needed
if [ -f "package.json" ]; then
echo "📦 Installing dependencies..."
npm install --silent
fi
# Start dev server (example for common workflow)
if [ -f "package.json" ] && grep -q '"dev"' package.json; then
echo "🚀 Starting dev server..."
npm run dev &
fi
```
**Special capability:** Persist environment variables using `$CLAUDE_ENV_FILE`:
```bash
echo "export PROJECT_TYPE=nodejs" >> "$CLAUDE_ENV_FILE"
```
See `examples/load-context.sh` for complete example.
**Teleport-specific input fields:**
- `is_teleport`: Boolean indicating if this session started via teleport
- `source`: Where the session came from ("web" or "cli") - only present for teleports
- `branch`: The git branch that was teleported - only present for teleports
See `examples/load-context.sh` and `examples/post-teleport.sh` for complete examples.
### SessionEnd
@@ -638,7 +689,7 @@ echo "$output" | jq .
| UserPromptSubmit | User input | Context, validation |
| Stop | Agent stopping | Completeness check |
| SubagentStop | Subagent done | Task validation |
| SessionStart | Session begins | Context loading |
| SessionStart | Session begins | Context loading (use `teleport` matcher for teleport-specific setup) |
| SessionEnd | Session ends | Cleanup, logging |
| PreCompact | Before compact | Preserve context |
| Notification | User notified | Logging, reactions |
@@ -679,6 +730,7 @@ Working examples in `examples/`:
- **`validate-write.sh`** - File write validation example
- **`validate-bash.sh`** - Bash command validation example
- **`load-context.sh`** - SessionStart context loading example
- **`post-teleport.sh`** - SessionStart teleport matcher setup example
### Utility Scripts

View File

@@ -0,0 +1,52 @@
#!/bin/bash
# Example SessionStart hook with "teleport" matcher for setting up environment
# after teleporting from web to CLI. This script pulls changes, installs
# dependencies, and starts the dev server.
set -euo pipefail
# Navigate to project directory
cd "$CLAUDE_PROJECT_DIR" || exit 0
echo "Setting up environment after teleport..."
# Pull latest changes if in a git repository
if [ -d ".git" ]; then
current_branch=$(git branch --show-current)
echo "🔄 Pulling latest changes for branch: $current_branch"
git pull origin "$current_branch" 2>/dev/null || echo "Could not pull (may be offline or no upstream)"
fi
# Install dependencies based on project type
if [ -f "package.json" ]; then
echo "📦 Installing Node.js dependencies..."
npm install --silent 2>/dev/null || npm install
fi
if [ -f "requirements.txt" ]; then
echo "🐍 Installing Python dependencies..."
pip install -r requirements.txt --quiet 2>/dev/null || pip install -r requirements.txt
fi
if [ -f "Cargo.toml" ]; then
echo "🦀 Building Rust project..."
cargo build 2>/dev/null || true
fi
# Start development server if available
if [ -f "package.json" ]; then
# Check for common dev server scripts
if grep -q '"dev:staging"' package.json; then
echo "🚀 Starting staging dev server..."
npm run dev:staging &
elif grep -q '"dev"' package.json; then
echo "🚀 Starting dev server..."
npm run dev &
elif grep -q '"start"' package.json; then
echo "🚀 Starting server..."
npm start &
fi
fi
echo "✅ Teleport complete! Environment ready."
exit 0

View File

@@ -344,3 +344,64 @@ fi
- Per-project settings
- Team-specific rules
- Dynamic validation criteria
## Pattern 11: Teleport Workflow Automation
Automate setup when teleporting sessions from web to CLI using the `teleport` matcher:
**SessionStart hook with teleport matcher:**
```json
{
"SessionStart": [
{
"matcher": "teleport",
"hooks": [
{
"type": "command",
"command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/post-teleport.sh"
}
]
}
]
}
```
**post-teleport.sh:**
```bash
#!/bin/bash
cd "$CLAUDE_PROJECT_DIR" || exit 0
# Pull latest changes
if [ -d ".git" ]; then
echo "🔄 Pulling latest changes..."
git pull origin "$(git branch --show-current)" 2>/dev/null || true
fi
# Install dependencies
if [ -f "package.json" ]; then
echo "📦 Installing dependencies..."
npm install --silent
fi
# Start dev server
if [ -f "package.json" ] && grep -q '"dev:staging"' package.json; then
echo "🚀 Starting staging dev server..."
npm run dev:staging &
elif [ -f "package.json" ] && grep -q '"dev"' package.json; then
echo "🚀 Starting dev server..."
npm run dev &
fi
echo "✅ Teleport complete! Environment ready."
```
**Available matchers for SessionStart:**
- `*` - All session starts (both fresh and teleported)
- `teleport` - Only teleported sessions (web → CLI)
- `fresh` - Only fresh sessions (not teleported)
**Use for:**
- Seamless web-to-CLI workflow transitions
- Automatic dev server startup after teleporting
- Pulling latest changes and installing dependencies
- Running project-specific setup scripts