Agent skill
surgical-injector
Safely inject new code into legacy codebases with risk containment. Use for feature flags, gradual rollouts, A/B testing new logic, or refactoring critical paths. Implements try-catch fallbacks, feature toggle architecture, and surgical separation of old/new code.
Install this agent skill to your Project
npx add-skill https://github.com/Jonely235/claude-skills/tree/main/.claude/skills/surgical-injector
SKILL.md
Surgical Injector
Inject new code into legacy systems with zero-downtime safety. Keep dirty legacy code and clean new code physically separated.
Core Philosophy
Do NOT rewrite old code. Instead:
- Extract new logic into a separate helper function
- Add a feature toggle (config/env variable)
- Wrap in try-catch that falls back to old behavior
- Document the surgery for future cleanup
The Surgery Pattern
Always follow this structure:
// [SURGERY] YYYY-MM-DD - Feature: X | Task: #123 | Deprecate: YYYY-MM-DD
function legacyFunction(input) {
// NEW CODE PATH (Guarded)
try {
if (shouldUseNewFeatureX()) {
return newFeatureXLogic(input);
}
} catch (error) {
// Fail silent - fall through to old logic
console.error('[SURGERY-FAIL] newFeatureXLogic:', error.message);
// TODO: Send to monitoring/bug tracking
}
// OLD CODE PATH (Original - Keep untouched)
return originalLogic(input);
}
// New logic extracted to separate function
function newFeatureXLogic(input) {
// Clean, isolated implementation
}
Step-by-Step Workflow
1. Locate the Target
Find the function or logic block to modify using Grep/Read:
Grep pattern: "function targetFunction|def target_function|class TargetClass"
Read the file to understand the current implementation.
2. Design the Toggle
Check if the project has existing config management:
# Look for environment files
Glob pattern: ".env*"
Glob pattern: "config/*"
Glob pattern: "config.js"
Glob pattern: "settings.py"
Toggle naming convention:
- Format:
ENABLE_NEW_<FEATURE_NAME>orUSE_<FEATURE>_V2 - Default:
false(old behavior) - Example:
ENABLE_NEW_PAYMENT_FLOW=true
Add the toggle flag:
In .env:
ENABLE_NEW_FEATURE_X=false
In config.js:
module.exports = {
ENABLE_NEW_FEATURE_X: process.env.ENABLE_NEW_FEATURE_X === 'true'
};
In settings.py:
ENABLE_NEW_FEATURE_X = os.environ.get('ENABLE_NEW_FEATURE_X', 'false') == 'true'
3. Extract New Logic
Create a NEW helper function with the new implementation:
// NEW: Clean implementation
function newFeatureXLogic(input) {
// Pure, testable logic
// No side effects where possible
return process(input);
}
Key principles:
- Keep it pure (same input = same output)
- Make it testable in isolation
- Add JSDoc/docstring explaining behavior
4. Add the Guard Clause
Inject the toggle check at the TOP of the original function:
function targetFunction(input) {
// === SURGERY GUARD ===
if (shouldUseNewFeatureX()) {
try {
return newFeatureXLogic(input);
} catch (error) {
logger.error('[SURGERY-FAIL] newFeatureXLogic', { error, input });
// Fall through to old logic
}
}
// === END SURGERY ===
// Original code untouched below
return oldImplementation(input);
}
Safety rules:
- NEW code runs first (top of function)
- Wrap in try-catch
- Log errors but NEVER re-throw
- Always fall back to old logic
5. Add Surgery Metadata
Add a comment block above the modified function:
/**
* [SURGERY] 2025-12-30
* Feature: New payment processing flow
* Task: #PROJ-123
* Toggle: ENABLE_NEW_PAYMENT_FLOW
*
* NEW: newPaymentFlow() - Uses Stripe API v3
* OLD: original code below - Uses Stripe API v2
*
* Deprecation: Remove old path by 2025-06-30 if stable
* Monitoring: Track 'surgery_payment_flow_fail' metric
*/
function processPayment(amount) {
// ... surgery pattern ...
}
6. Add Monitoring (Optional but Recommended)
Log the toggle state and failures:
try {
if (shouldUseNewFeatureX()) {
metrics.increment('surgery_feature_x_attempt');
return newFeatureXLogic(input);
}
} catch (error) {
metrics.increment('surgery_feature_x_fail');
console.error('[SURGERY-FAIL]', error);
}
Language-Specific Patterns
JavaScript/Node.js
// Toggle helper
function shouldUseNewFeatureX() {
return process.env.ENABLE_NEW_FEATURE_X === 'true';
}
// Surgery (Sync)
function legacyFunction(input) {
if (shouldUseNewFeatureX()) {
try {
return newFeatureXLogic(input);
} catch (error) {
console.error('[SURGERY-FAIL]', error);
}
}
return oldLogic(input);
}
// Surgery (Async)
async function legacyFunctionAsync(input) {
if (shouldUseNewFeatureX()) {
try {
return await newFeatureXLogicAsync(input);
} catch (error) {
console.error('[SURGERY-FAIL]', error);
}
}
return await oldLogicAsync(input);
}
// Async with dynamic toggle check (e.g., from database/remote config)
async function legacyFunctionDynamicToggle(input) {
if (await shouldUseNewFeatureXFromConfig()) {
try {
return await newFeatureXLogicAsync(input);
} catch (error) {
console.error('[SURGERY-FAIL]', error);
}
}
return await oldLogicAsync(input);
}
Python
import os
import logging
logger = logging.getLogger(__name__)
# Toggle
def should_use_new_feature_x():
return os.environ.get('ENABLE_NEW_FEATURE_X', 'false') == 'true'
# Surgery (Sync)
def legacy_function(input):
if should_use_new_feature_x():
try:
return new_feature_x_logic(input)
except Exception as e:
logger.error('[SURGERY-FAIL] new_feature_x_logic', exc_info=e)
return old_logic(input)
# Surgery (Async)
async def legacy_function_async(input):
if should_use_new_feature_x():
try:
return await new_feature_x_logic_async(input)
except Exception as e:
logger.error('[SURGERY-FAIL] new_feature_x_logic_async', exc_info=e)
return await old_logic_async(input)
# Async with dynamic toggle (e.g., from Redis/remote config)
async def legacy_function_dynamic_toggle(input):
if await should_use_new_feature_x_from_config():
try:
return await new_feature_x_logic_async(input)
except Exception as e:
logger.error('[SURGERY-FAIL] new_feature_x_logic_async', exc_info=e)
return await old_logic_async(input)
TypeScript
const ENABLE_NEW_FEATURE_X = process.env.ENABLE_NEW_FEATURE_X === 'true';
// Surgery (Sync)
function legacyFunction(input: InputType): OutputType {
if (ENABLE_NEW_FEATURE_X) {
try {
return newFeatureXLogic(input);
} catch (error) {
console.error('[SURGERY-FAIL]', error);
}
}
return oldLogic(input);
}
// Surgery (Async)
async function legacyFunctionAsync(input: InputType): Promise<OutputType> {
if (ENABLE_NEW_FEATURE_X) {
try {
return await newFeatureXLogicAsync(input);
} catch (error) {
console.error('[SURGERY-FAIL]', error);
}
}
return await oldLogicAsync(input);
}
// Async with dynamic toggle check
async function legacyFunctionDynamicToggle(input: InputType): Promise<OutputType> {
if (await shouldUseNewFeatureXFromConfig()) {
try {
return await newFeatureXLogicAsync(input);
} catch (error) {
console.error('[SURGERY-FAIL]', error);
}
}
return await oldLogicAsync(input);
}
Go
var enableNewFeatureX = os.Getenv("ENABLE_NEW_FEATURE_X") == "true"
func legacyFunction(input Input) Output {
if enableNewFeatureX {
if result, err := newFeatureXLogic(input); err == nil {
return result
} else {
log.Printf("[SURGERY-FAIL] newFeatureXLogic: %v", err)
}
}
return oldLogic(input)
}
Java
private static final boolean ENABLE_NEW_FEATURE_X =
"true".equals(System.getenv("ENABLE_NEW_FEATURE_X"));
public Output legacyFunction(Input input) {
if (ENABLE_NEW_FEATURE_X) {
try {
return newFeatureXLogic(input);
} catch (Exception e) {
log.error("[SURGERY-FAIL] newFeatureXLogic", e);
}
}
return oldLogic(input);
}
C#
using Microsoft.Extensions.Logging;
// Toggle helper (in appsettings.json: "EnableNewFeatureX": false)
private static bool ShouldUseNewFeatureX() =>
bool.TryParse(Environment.GetEnvironmentVariable("ENABLE_NEW_FEATURE_X"), out var enabled) && enabled;
// Or using IConfiguration
private readonly IConfiguration _config;
private bool ShouldUseNewFeatureX() => _config.GetValue<bool>("EnableNewFeatureX", false);
// Surgery
public Output LegacyFunction(Input input)
{
if (ShouldUseNewFeatureX())
{
try
{
return NewFeatureXLogic(input);
}
catch (Exception ex)
{
_logger.LogError(ex, "[SURGERY-FAIL] NewFeatureXLogic");
}
}
return OldLogic(input);
}
// Async version
public async Task<Output> LegacyFunctionAsync(Input input)
{
if (ShouldUseNewFeatureX())
{
try
{
return await NewFeatureXLogicAsync(input);
}
catch (Exception ex)
{
_logger.LogError(ex, "[SURGERY-FAIL] NewFeatureXLogicAsync");
}
}
return await OldLogicAsync(input);
}
Configuration in appsettings.json:
{
"EnableNewFeatureX": false,
"FeatureFlags": {
"EnableNewFeatureX": false
}
}
Or using appsettings.Development.json:
{
"EnableNewFeatureX": true // Enable locally for testing
}
Angular (TypeScript + Services)
// config.service.ts - Feature toggle management
@Injectable({ providedIn: 'root' })
export class ConfigService {
private featureFlags = new Map<string, boolean>();
constructor(@Inject(PLATFORM_ID) private platformId: Object) {}
// Load from environment or API
loadFeatureFlags(): void {
if (isPlatformBrowser(this.platformId)) {
this.featureFlags.set('ENABLE_NEW_FEATURE_X',
environment.enableNewFeatureX === true
);
}
}
isFeatureEnabled(featureName: string): boolean {
return this.featureFlags.get(featureName) ?? false;
}
}
// component.ts - Surgical pattern in component methods
@Component({ /* ... */ })
export class PaymentComponent implements OnInit {
constructor(private config: ConfigService, private logger: LoggerService) {}
processPayment(amount: number): PaymentResult {
// === SURGERY GUARD ===
if (this.config.isFeatureEnabled('ENABLE_NEW_PAYMENT_FLOW')) {
try {
return this.newPaymentFlow(amount);
} catch (error) {
this.logger.error('[SURGERY-FAIL] newPaymentFlow', error);
// Fall through to old logic
}
}
// === END SURGERY ===
return this.oldPaymentFlow(amount);
}
// NEW: Clean implementation
private newPaymentFlow(amount: number): PaymentResult {
return this.paymentServiceV3.process(amount);
}
// OLD: Original implementation
private oldPaymentFlow(amount: number): PaymentResult {
return this.paymentServiceV2.process(amount);
}
}
// Async version for HTTP calls
processPaymentAsync(amount: number): Observable<PaymentResult> {
if (this.config.isFeatureEnabled('ENABLE_NEW_PAYMENT_FLOW')) {
return this.paymentServiceV3.process(amount).pipe(
catchError((error) => {
this.logger.error('[SURGERY-FAIL] newPaymentFlow', error);
// Fall back to old logic
return this.paymentServiceV2.process(amount);
})
);
}
return this.paymentServiceV2.process(amount);
}
Configuration in environment.ts:
export const environment = {
production: false,
enableNewFeatureX: false // Default to false
};
Configuration in environment.prod.ts:
export const environment = {
production: true,
enableNewFeatureX: false // Control rollout in production
};
Angular-specific considerations:
- Use
isPlatformBrowsercheck to avoid SSR issues - Leverage RxJS
catchErrorfor Observable-based surgery - Store feature flags in a service for easy toggling
- Consider remote config services (LaunchDarkly, Firebase Remote Config) for runtime toggles
Rollback Procedure
If new code causes issues:
-
Immediate rollback: Set toggle to
falsebash# .env ENABLE_NEW_FEATURE_X=false -
No redeploy needed - toggle takes effect on restart/reload
-
Investigate logs for
[SURGERY-FAIL]entries -
Fix new logic and increment toggle version
bashENABLE_NEW_FEATURE_X_V2=false # Fixed version, disabled by default
Cleanup and Deprecation
After the new code proves stable (typically 2-4 weeks):
- Remove the old code path
- Remove the toggle check
- Update function to call new logic directly
- Remove the helper function (inline if simple)
// BEFORE: Surgery pattern
function processPayment(input) {
if (shouldUseNewFlow()) {
try { return newFlow(input); } catch (e) { /* log */ }
}
return oldFlow(input); // Remove this
}
// AFTER: Clean implementation
function processPayment(input) {
return newFlow(input); // Direct call
}
Update surgery comment to document completion:
/**
* [SURGERY-COMPLETE] 2025-12-30 -> 2025-01-15
* Feature: New payment flow
* Status: Stable. Old path removed.
* Migration: PROJ-123
*/
function processPayment(input) {
return newFlow(input);
}
When to Use This Skill
Trigger for these user requests:
- "Add a feature flag to this function"
- "I want to A/B test this new logic"
- "Safely refactor this critical function"
- "Add a kill switch to this feature"
- "I need to deploy this but can't afford downtime"
- "Gradually roll out this change"
Do NOT use for:
- Simple variable renaming
- Adding comments or documentation
- Non-critical code paths
- Greenfield projects (no legacy code)
Anti-Patterns to Avoid
DON'T: Modify the old code path
- Keep original implementation untouched
DON'T: Re-throw exceptions in the catch block
- Let it fall through to old logic silently
DON'T: Skip the toggle
- Hardcoding
truedefeats the safety mechanism
DON'T: Forget logging
- Without
[SURGERY-FAIL]logs, debugging is impossible
DON'T: Make the new function depend on the old code's state
- Keep new logic independent and pure
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
surgical-injector
Safely inject new code into legacy codebases with risk containment. Use for feature flags, gradual rollouts, A/B testing new logic, or refactoring critical paths. Implements try-catch fallbacks, feature toggle architecture, and surgical separation of old/new code.
blast-radius-analysis
Analyze the impact of code changes by mapping call graphs and identifying all direct and indirect dependencies. Use when users ask about blast radius analysis, code change impact, who calls a function, downstream dependencies, or risk assessment before refactoring. Traces call chains, identifies high-risk modules, and provides ranked impact analysis.
first-principles
code-cartographer
Analyze and map code structure, data flow, and dependencies in legacy codebases. Use for understanding call stacks, dependency trees, side effects, risk profiles, and generating Mermaid diagrams. Ideal for legacy codebases with zero tests.
skill-creator
Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.
code-cartographer
Analyze and map code structure, data flow, and dependencies in legacy codebases. Use for understanding call stacks, dependency trees, side effects, risk profiles, and generating Mermaid diagrams. Ideal for legacy codebases with zero tests.
Didn't find tool you were looking for?